Giới thiệu
Thật không may, không có cách nào để đặt SearchView
kiểu trường văn bản bằng cách sử dụng các chủ đề, kiểu và kế thừa trong XML như bạn có thể làm với nền của các mục trong trình đơn thả xuống ActionBar . Điều này là do selectableItemBackground
được liệt kê như styleable trong R.stylable
, trong khi searchViewTextField
(theme thuộc tính mà chúng ta đang quan tâm) không được. Do đó, chúng tôi không thể truy cập dễ dàng từ bên trong các tài nguyên XML (bạn sẽ gặp No resource found that matches the given name: attr 'android:searchViewTextField'
lỗi).
Đặt nền trường văn bản SearchView từ mã
Vì vậy, cách duy nhất để thay thế nền của SearchView
trường văn bản một cách chính xác là vào bên trong nó, có quyền truy cập vào chế độ xem có nền được thiết lập dựa trên searchViewTextField
và thiết lập nền của chúng ta.
LƯU Ý: Giải pháp bên dưới chỉ phụ thuộc vào id ( android:id/search_plate
) của phần tử bên trong SearchView
, do đó, phiên bản SDK độc lập hơn so với giao dịch trẻ em (ví dụ: sử dụng searchView.getChildAt(0)
để có chế độ xem đúng trong SearchView
), nhưng không chống đạn. Đặc biệt là nếu một số nhà sản xuất quyết định thực hiện lại phần bên trong SearchView
và phần tử có id được đề cập ở trên - mã sẽ không hoạt động.
Trong SDK, nền cho trường văn bản SearchView
được khai báo thông qua chín bản vá , vì vậy chúng tôi sẽ thực hiện theo cách tương tự. Bạn có thể tìm thấy hình ảnh png gốc trong thư mục drawable-mdpi của kho lưu trữ git Android . Chúng tôi quan tâm đến hai hình ảnh. Một trạng thái khi trường văn bản được chọn (có tên là textfield_search_selected_holo_light.9.png ) và một trạng thái không (tên là textfield_search_default_holo_light.9.png ).
Thật không may, bạn sẽ phải tạo các bản sao cục bộ của cả hai hình ảnh, ngay cả khi bạn chỉ muốn tùy chỉnh trạng thái tập trung . Điều này là do textfield_search_default_holo_light
không có trong R.drawable . Do đó, nó không dễ dàng truy cập thông qua @android:drawable/textfield_search_default_holo_light
, có thể được sử dụng trong bộ chọn hiển thị bên dưới, thay vì tham chiếu có thể vẽ cục bộ.
LƯU Ý: Tôi đã sử dụng chủ đề Holo Light làm cơ sở, nhưng bạn có thể làm tương tự với Holo Dark . Dường như không có sự khác biệt thực sự trong các bản vá 9 trạng thái được chọn giữa các chủ đề Sáng và Tối . Tuy nhiên, có một sự khác biệt trong 9 bản vá cho trạng thái mặc định (xem Light vs Dark ). Vì vậy, có lẽ không cần phải tạo các bản sao 9 miếng cục bộ cho trạng thái được chọn , cho cả chủ đề Tối và Sáng (giả sử rằng bạn muốn xử lý cả hai và làm cho cả hai trông giống như trong Chủ đề Holo ). Chỉ cần tạo một bản sao cục bộ và sử dụng nó trongbộ chọn có thể vẽ cho cả hai chủ đề.
Bây giờ, bạn sẽ cần chỉnh sửa chín bản vá đã tải xuống theo nhu cầu của mình (tức là thay đổi màu xanh lam thành màu đỏ). Bạn có thể xem tệp bằng công cụ vẽ 9 bản vá để kiểm tra xem nó có được xác định chính xác sau khi chỉnh sửa không.
Tôi đã chỉnh sửa các tệp bằng GIMP bằng công cụ bút chì một pixel (khá dễ) nhưng có thể bạn sẽ sử dụng công cụ của riêng mình. Đây là bản vá 9 tùy chỉnh của tôi cho trạng thái tập trung :
LƯU Ý: Để đơn giản, tôi chỉ sử dụng hình ảnh cho mật độ mdpi . Bạn sẽ phải tạo 9 bản vá cho nhiều mật độ màn hình nếu, bạn muốn có kết quả tốt nhất trên mọi thiết bị. Hình ảnh cho Holo SearchView
có thể được tìm thấy trong mdpi , hdpi và xhdpi drawable.
Bây giờ, chúng ta sẽ cần tạo bộ chọn có thể vẽ, để hình ảnh phù hợp được hiển thị dựa trên trạng thái xem. Tạo tập tin res/drawable/texfield_searchview_holo_light.xml
với nội dung sau:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true"
android:drawable="@drawable/textfield_search_selected_holo_light" />
<item android:drawable="@drawable/textfield_search_default_holo_light" />
</selector>
Chúng tôi sẽ sử dụng drawable được tạo ở trên để đặt nền cho LinearLayout
chế độ xem chứa trường văn bản bên trong SearchView
- id của nó là android:id/search_plate
. Vì vậy, đây là cách để làm điều này một cách nhanh chóng trong mã, khi tạo menu tùy chọn:
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
// Getting SearchView from XML layout by id defined there - my_search_view in this case
SearchView searchView = (SearchView) menu.findItem(R.id.my_search_view).getActionView();
// Getting id for 'search_plate' - the id is part of generate R file,
// so we have to get id on runtime.
int searchPlateId = searchView.getContext().getResources().getIdentifier("android:id/search_plate", null, null);
// Getting the 'search_plate' LinearLayout.
View searchPlate = searchView.findViewById(searchPlateId);
// Setting background of 'search_plate' to earlier defined drawable.
searchPlate.setBackgroundResource(R.drawable.textfield_searchview_holo_light);
return super.onCreateOptionsMenu(menu);
}
}
Hiệu quả cuối cùng
Đây là ảnh chụp màn hình của kết quả cuối cùng:
Làm thế nào tôi có được điều này
Tôi nghĩ rằng nó đáng để đo lường cách tôi đạt được điều này, để cách tiếp cận này có thể được sử dụng khi tùy chỉnh các chế độ xem khác.
Kiểm tra bố cục xem
Tôi đã kiểm tra SearchView
bố cục trông như thế nào. Trong công cụ tìm kiếm SearchView, người ta có thể tìm thấy một dòng làm tăng bố cục:
inflater.inflate(R.layout.search_view, this, true);
Bây giờ chúng ta biết rằng SearchView
bố trí là trong tập tin có tên res/layout/search_view.xml
. Nhìn vào search_view.xml chúng ta có thể tìm thấy một LinearLayout
phần tử bên trong (có id search_plate
) có android.widget.SearchView$SearchAutoComplete
bên trong nó (trông giống như trường văn bản xem tìm kiếm của chúng ta):
<LinearLayout
android:id="@+id/search_plate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:orientation="horizontal"
android:background="?android:attr/searchViewTextField">
Bây giờ, chúng tôi bây giờ nền được đặt dựa trên searchViewTextField
thuộc tính của chủ đề hiện tại .
Điều tra thuộc tính (nó có thể dễ dàng giải quyết?)
Để kiểm tra cách đặt searchViewTextField
thuộc tính, chúng tôi điều tra res / value / Themes.xml . Có một nhóm các thuộc tính liên quan đến SearchView
mặc định Theme
:
<style name="Theme">
<!-- (...other attributes present here...) -->
<!-- SearchView attributes -->
<item name="searchDropdownBackground">@android:drawable/spinner_dropdown_background</item>
<item name="searchViewTextField">@drawable/textfield_searchview_holo_dark</item>
<item name="searchViewTextFieldRight">@drawable/textfield_searchview_right_holo_dark</item>
<item name="searchViewCloseIcon">@android:drawable/ic_clear</item>
<item name="searchViewSearchIcon">@android:drawable/ic_search</item>
<item name="searchViewGoIcon">@android:drawable/ic_go</item>
<item name="searchViewVoiceIcon">@android:drawable/ic_voice_search</item>
<item name="searchViewEditQuery">@android:drawable/ic_commit_search_api_holo_dark</item>
<item name="searchViewEditQueryBackground">?attr/selectableItemBackground</item>
Chúng tôi thấy rằng đối với chủ đề mặc định, giá trị là @drawable/textfield_searchview_holo_dark
. Đối với Theme.Light
giá trị cũng được đặt trong tập tin đó .
Bây giờ, sẽ thật tuyệt nếu thuộc tính này có thể truy cập được thông qua R.stylizable , nhưng, thật không may là nó không. Để so sánh, hãy xem các thuộc tính chủ đề khác hiện diện cả trong Themes.xml và R.attr như textAppparent hoặc selectableItemBackground . Nếu searchViewTextField
đã có mặt trong R.attr
(và R.stylable
), chúng ta chỉ cần sử dụng bộ chọn có thể vẽ được khi xác định chủ đề cho toàn bộ ứng dụng của mình bằng XML. Ví dụ:
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="AppTheme" parent="android:Theme.Light">
<item name="android:searchViewTextField">@drawable/textfield_searchview_holo_light</item>
</style>
</resources>
Những gì cần được sửa đổi?
Bây giờ chúng tôi biết rằng chúng tôi sẽ phải truy cập search_plate
thông qua mã. Tuy nhiên, chúng ta vẫn không biết nó sẽ trông như thế nào. Nói tóm lại, chúng tôi tìm kiếm các drawable được sử dụng làm giá trị trong các chủ đề mặc định: textfield_searchview_holo_dark.xml và textfield_searchview_holo_light.xml . Nhìn vào nội dung, chúng ta thấy rằng drawable là selector
tham chiếu hai drawable khác (xảy ra là 9-patch sau này) dựa trên trạng thái view. Bạn có thể tìm thấy các bản vẽ 9 bản vá tổng hợp từ (gần như) tất cả các phiên bản Android trên androiddrawables.com
Tùy chỉnh
Chúng tôi nhận ra đường màu xanh lam trong một trong 9 miếng vá , vì vậy chúng tôi tạo bản sao cục bộ của nó và thay đổi màu sắc theo ý muốn.