Intro
Leider gibt es keine Möglichkeit, den SearchView
Textfeldstil mithilfe von Themen, Stilen und Vererbung in XML festzulegen, wie dies mit dem Hintergrund von Elementen in der Dropdown-Liste "ActionBar" möglich ist . Dies liegt daran , selectableItemBackground
wie styleable aufgeführt wird in R.stylable
, während searchViewTextField
(Thema Attribut , das uns interessiert) nicht. Daher können wir nicht einfach aus XML-Ressourcen darauf zugreifen (es wird eine No resource found that matches the given name: attr 'android:searchViewTextField'
Fehlermeldung angezeigt).
Festlegen des SearchView-Textfeldhintergrunds aus dem Code
Die einzige Möglichkeit, den Hintergrund eines SearchView
Textfelds richtig zu ersetzen, besteht darin, in die Interna zu gelangen, Zugriff auf eine Ansicht zu erhalten, für die der Hintergrund basierend auf searchViewTextField
unserem eigenen festgelegt und festgelegt wurde.
ANMERKUNG: Die unten stehende Lösung hängt nur von der ID ( android:id/search_plate
) des darin enthaltenen Elements ab. Daher SearchView
ist die SDK-Version unabhängiger als das Durchlaufen von Kindern (z. B. Verwenden searchView.getChildAt(0)
, um zur richtigen Ansicht innerhalb des Elements zu gelangen SearchView
), sie ist jedoch nicht kugelsicher. Insbesondere wenn ein Hersteller beschließt, Interna von neu zu implementieren SearchView
und ein Element mit der oben genannten ID nicht vorhanden ist, funktioniert der Code nicht.
Im SDK wird der Hintergrund für das Textfeld in SearchView
durch neun Patches deklariert , sodass wir es auf die gleiche Weise tun. Sie können Original finden png Bilder in ziehbar-MDPI Verzeichnis von Android Git Repository . Wir sind an zwei Bildern interessiert. Eine für den Status, wenn ein Textfeld ausgewählt ist (mit dem Namen textfield_search_selected_holo_light.9.png ) und eine für den Ort, an dem es nicht ausgewählt ist (mit dem Namen textfield_search_default_holo_light.9.png ).
Leider müssen Sie lokale Kopien beider Bilder erstellen, auch wenn Sie nur den fokussierten Status anpassen möchten . Dies liegt daran, dass textfield_search_default_holo_light
in R.drawable nicht vorhanden ist . Daher ist es nicht leicht zugänglich über @android:drawable/textfield_search_default_holo_light
, was in der unten gezeigten Auswahl verwendet werden könnte, anstatt auf lokale Zeichen zu verweisen.
HINWEIS: Ich habe das Holo Light- Thema als Basis verwendet, aber Sie können dasselbe mit Holo Dark tun . Es scheint, dass es in ausgewählten Status- 9-Patches keinen wirklichen Unterschied zwischen hellen und dunklen Themen gibt. Es gibt jedoch einen Unterschied bei 9 Patches für den Standardstatus (siehe Hell gegen Dunkel ). Daher ist es wahrscheinlich nicht erforderlich, lokale Kopien von 9 Patches für den ausgewählten Status sowohl für dunkle als auch für helle Themen zu erstellen (vorausgesetzt, Sie möchten beide behandeln und beide sehen genauso aus wie im Holo-Thema ). Erstellen Sie einfach eine lokale Kopie und verwenden Sie sie inAuswahl für beide Themen zeichnbar .
Jetzt müssen Sie die heruntergeladenen neun Patches nach Ihren Wünschen bearbeiten (dh die blaue Farbe in eine rote ändern). Sie können die Datei mit dem Draw 9-Patch-Tool überprüfen, um zu überprüfen, ob sie nach der Bearbeitung korrekt definiert ist.
Ich habe Dateien mit GIMP mit einem Ein-Pixel-Stift-Werkzeug bearbeitet (ziemlich einfach), aber Sie werden wahrscheinlich Ihr eigenes Werkzeug verwenden. Hier ist mein angepasster 9-Patch für den fokussierten Zustand :
HINWEIS: Der Einfachheit halber habe ich nur Bilder für die MDPI- Dichte verwendet. Sie müssen 9 Patches für mehrere Bildschirmdichten erstellen , wenn Sie auf jedem Gerät das beste Ergebnis erzielen möchten. Bilder für Holo SearchView
finden Sie in mdpi , hdpi und xhdpi drawable.
Jetzt müssen wir einen zeichnbaren Selektor erstellen, damit das richtige Bild basierend auf dem Ansichtsstatus angezeigt wird. Erstellen Sie eine Datei res/drawable/texfield_searchview_holo_light.xml
mit folgendem Inhalt:
<?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>
Wir werden das oben erstellte Drawable verwenden, um den Hintergrund für die LinearLayout
Ansicht festzulegen, in der sich das Textfeld befindet SearchView
- seine ID ist android:id/search_plate
. So geht's im Code beim Erstellen des Optionsmenüs schnell:
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);
}
}
Endeffekt
Hier ist der Screenshot des Endergebnisses:
Wie ich dazu gekommen bin
Ich denke, es lohnt sich zu überlegen, wie ich dazu gekommen bin, damit dieser Ansatz beim Anpassen anderer Ansichten verwendet werden kann.
Ansichtslayout auschecken
Ich habe überprüft, wie das SearchView
Layout aussieht. Im SearchView-Konstruktor finden Sie eine Linie, die das Layout aufbläst :
inflater.inflate(R.layout.search_view, this, true);
Jetzt wissen wir, dass das SearchView
Layout in der Datei mit dem Namen ist res/layout/search_view.xml
. Wenn wir in search_view.xml schauen , können wir ein inneres LinearLayout
Element (mit ID search_plate
) finden, das android.widget.SearchView$SearchAutoComplete
darin enthalten ist (sieht aus wie unser Textfeld in der Suchansicht ):
<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">
Jetzt, da der Hintergrund basierend auf dem searchViewTextField
Attribut des aktuellen Themas festgelegt ist .
Untersuchungsattribut (ist es leicht einstellbar?)
Um zu überprüfen, wie das searchViewTextField
Attribut festgelegt ist, untersuchen wir res / values / theme.xml . SearchView
Standardmäßig gibt es eine Gruppe von Attributen 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>
Wir sehen, dass für das Standardthema der Wert ist @drawable/textfield_searchview_holo_dark
. Für Theme.Light
Wert wird auch in dieser Datei gesetzt .
Nun, es wäre großartig, wenn dieses Attribut über R.styleable zugänglich wäre , aber leider nicht. Zum Vergleich : Andere Thema Attribute , die vorhanden sind beide in themes.xml und R.attr wie textAppearance oder selectableItemBackground . Wenn searchViewTextField
in R.attr
(und R.stylable
) vorhanden, könnten wir einfach unseren zeichnbaren Selektor verwenden, um das Thema für unsere gesamte Anwendung in XML zu definieren. Beispielsweise:
<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>
Was sollte geändert werden?
Jetzt wissen wir, dass wir search_plate
über Code zugreifen müssen. Wir wissen jedoch immer noch nicht, wie es aussehen soll. Kurz gesagt, wir suchen nach Drawables, die in Standardthemen als Werte verwendet werden: textfield_searchview_holo_dark.xml und textfield_searchview_holo_light.xml . Wenn wir uns den Inhalt ansehen, sehen wir, dass das Drawable selector
zwei andere Drawables (die später 9 Patches sind) basierend auf dem Ansichtsstatus referenziert. Auf androiddrawables.com finden Sie aggregierte 9-Patch-Drawables von (fast) allen Android- Versionen
Customizing
Wir erkennen die blaue Linie in einem der 9 Patches , erstellen also eine lokale Kopie davon und ändern die Farben nach Wunsch.