Intro
Niestety nie ma sposobu na ustawienie SearchView
stylu pola tekstowego za pomocą motywów, stylów i dziedziczenia w XML, tak jak można to zrobić z tłem elementów w menu rozwijanym ActionBar . Dzieje się tak, ponieważ selectableItemBackground
jest wymieniony jako podlegający stylizacji w R.stylable
, podczas gdy searchViewTextField
(atrybut motywu, który nas interesuje) nie. Dlatego nie możemy uzyskać do niego łatwego dostępu z zasobów XML (pojawi się No resource found that matches the given name: attr 'android:searchViewTextField'
błąd).
Ustawianie tła pola tekstowego SearchView z kodu
Tak więc jedynym sposobem na poprawne podstawienie tła SearchView
pola tekstowego jest wejście do jego wnętrza, uzyskanie dostępu do widoku, który ma ustawione tło searchViewTextField
i ustawienie własnego.
UWAGA: Poniższe rozwiązanie zależy tylko od id ( android:id/search_plate
) elementu wewnątrz SearchView
, więc jest bardziej niezależne od wersji SDK niż przechodzenie dzieci (np. Użycie, searchView.getChildAt(0)
aby uzyskać właściwy widok wewnątrz SearchView
), ale nie jest kuloodporne. Zwłaszcza jeśli jakiś producent zdecyduje się na ponowne zaimplementowanie elementów wewnętrznych SearchView
i brak elementu o podanym powyżej id - kod nie zadziała.
W SDK tło pola tekstowego w SearchView
jest deklarowane za pomocą dziewięciu łat , więc zrobimy to w ten sam sposób. Oryginalne obrazy png można znaleźć w katalogu drawable-mdpi repozytorium git systemu Android . Interesują nas dwa obrazy. Jeden dla stanu, gdy zaznaczone jest pole tekstowe (o nazwie textfield_search_selected_holo_light.9.png ), a drugi dla miejsca, w którym go nie ma (o nazwie textfield_search_default_holo_light.9.png ).
Niestety, będziesz musiał utworzyć lokalne kopie obu obrazów, nawet jeśli chcesz dostosować tylko stan skupienia . Dzieje się tak, ponieważ textfield_search_default_holo_light
nie ma go w R.drawable . W związku z tym nie jest łatwo dostępny za pomocą @android:drawable/textfield_search_default_holo_light
, którego można użyć w selektorze pokazanym poniżej, zamiast odwoływania się do lokalnego drawable.
UWAGA: użyłem motywu Holo Light jako podstawy, ale możesz zrobić to samo z Holo Dark . Wydaje się, że nie ma istotnej różnicy w wybranych państwowych 9-łaty między Światła i Ciemności tematów. Istnieje jednak różnica w 9 łatach dla stanu domyślnego (patrz Jasny kontra Ciemny ). Więc prawdopodobnie nie ma potrzeby tworzenia lokalnych kopii 9 poprawek dla wybranego stanu , zarówno dla motywów Dark i Light (zakładając, że chcesz obsłużyć oba i sprawić, by wyglądały tak samo jak w Holo Theme ). Po prostu wykonaj jedną lokalną kopię i użyj jej wselektor do rysowania dla obu tematów.
Teraz musisz edytować pobrane dziewięć poprawek według swoich potrzeb (tj. Zmieniając kolor niebieski na czerwony). Możesz rzucić okiem na plik za pomocą narzędzia Draw 9-patch, aby sprawdzić, czy jest poprawnie zdefiniowany po edycji.
Edytowałem pliki za pomocą GIMP-a z jednym pikselowym narzędziem ołówka (dość łatwe), ale prawdopodobnie użyjesz własnego narzędzia. Oto moja dostosowana łatka 9 dla stanu skupienia :
UWAGA: Dla uproszczenia użyłem tylko obrazów dla gęstości mdpi . Będziesz musiał utworzyć 9 łatek dla wielu gęstości ekranu, jeśli chcesz uzyskać najlepszy wynik na dowolnym urządzeniu. Obrazy dla Holo SearchView
można znaleźć w formacie mdpi , hdpi i xhdpi do rysowania.
Teraz musimy utworzyć selektor do rysowania, aby odpowiedni obraz był wyświetlany na podstawie stanu widoku. Utwórz plik res/drawable/texfield_searchview_holo_light.xml
z następującą zawartością:
<?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>
Użyjemy powyższego utworzonego drawable, aby ustawić tło dla LinearLayout
widoku, który zawiera pole tekstowe SearchView
- jego identyfikator to android:id/search_plate
. Oto jak to zrobić szybko w kodzie podczas tworzenia menu opcji:
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);
}
}
Efekt końcowy
Oto zrzut ekranu końcowego wyniku:
Jak do tego doszedłem
Myślę, że warto poznać, jak do tego doszedłem, aby to podejście można było wykorzystać podczas dostosowywania innych widoków.
Sprawdzam układ widoku
Sprawdziłem, jak SearchView
wygląda układ. W konstruktorze SearchView można znaleźć wiersz, który zawyża układ:
inflater.inflate(R.layout.search_view, this, true);
Teraz wiemy, że SearchView
układ znajduje się w pliku o nazwie res/layout/search_view.xml
. Spoglądając na search_view.xml , możemy znaleźć wewnętrzny LinearLayout
element (z id search_plate
), który ma android.widget.SearchView$SearchAutoComplete
wewnątrz (wygląda jak nasze pole tekstowe widoku wyszukiwania):
<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">
Teraz wiemy, że tło jest ustawione na podstawie searchViewTextField
atrybutu bieżącego motywu .
Badanie atrybutu (czy jest to łatwe do ustalenia?)
Aby sprawdzić, jak searchViewTextField
ustawiany jest atrybut, sprawdzamy plik res / values / themes.xml . Istnieje grupa atrybutów powiązanych SearchView
domyślnie 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>
Widzimy, że dla motywu domyślnego wartością jest @drawable/textfield_searchview_holo_dark
. Dla Theme.Light
wartości jest także ustawić w tym pliku .
Byłoby wspaniale, gdyby ten atrybut był dostępny przez R.styleable , ale niestety tak nie jest. Dla porównania zobacz inne rozrywki atrybuty, które są obecne zarówno w themes.xml i R.attr jak textAppearance lub selectableItemBackground . Gdyby searchViewTextField
był obecny w R.attr
(i R.stylable
), moglibyśmy po prostu użyć naszego selektora do rysowania podczas definiowania motywu dla całej naszej aplikacji w XML. Na przykład:
<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>
Co należy zmodyfikować?
Teraz wiemy, że będziemy musieli uzyskać dostęp search_plate
przez kod. Jednak nadal nie wiemy, jak to powinno wyglądać. Krótko mówiąc, wyszukujemy obiekty do rysowania używane jako wartości w domyślnych motywach: textfield_searchview_holo_dark.xml i textfield_searchview_holo_light.xml . Patrząc na treść, widzimy, że to, selector
co można rysować, odnosi się do dwóch innych rysunków (które później są 9-łatkami) w oparciu o stan widoku. Zagregowane elementy do rysowania z 9 łatkami z (prawie) wszystkich wersji Androida można znaleźć na androiddrawables.com
Dostosowywanie
Rozpoznajemy niebieską linię w jednej z 9 łat , więc tworzymy jej lokalną kopię i zmieniamy kolory według potrzeb.