Intro
Sfortunatamente non c'è modo di impostare lo SearchView
stile del campo di testo usando temi, stili ed ereditarietà in XML come puoi fare con lo sfondo degli elementi nel menu a discesa ActionBar . Questo perché selectableItemBackground
è elencato come stilizzabile in R.stylable
, mentre searchViewTextField
(attributo del tema a cui siamo interessati) non lo è. Pertanto, non possiamo accedervi facilmente dalle risorse XML (riceverai un No resource found that matches the given name: attr 'android:searchViewTextField'
errore).
Impostazione dello sfondo del campo di testo di SearchView dal codice
Quindi, l'unico modo per sostituire correttamente lo sfondo del SearchView
campo di testo è entrare nei suoi interni, acquisire l'accesso alla visualizzazione che ha lo sfondo impostato in base searchViewTextField
e impostare il nostro.
NOTA: la soluzione seguente dipende solo dall'id ( android:id/search_plate
) dell'elemento all'interno SearchView
, quindi è più indipendente dalla versione dell'SDK rispetto all'attraversamento dei figli (ad esempio, utilizzando searchView.getChildAt(0)
per arrivare alla vista giusta all'interno SearchView
), ma non è a prova di proiettile. Soprattutto se qualche produttore decide di reimplementare gli interni SearchView
e l'elemento con l'ID sopra menzionato non è presente, il codice non funzionerà.
In SDK, lo sfondo del campo di testo in SearchView
è dichiarato tramite nove patch , quindi lo faremo allo stesso modo. Puoi trovare immagini png originali nella directory drawable-mdpi del repository git di Android . Ci interessano due immagini. Uno per lo stato in cui il campo di testo è selezionato (denominato textfield_search_selected_holo_light.9.png ) e uno per dove non lo è (denominato textfield_search_default_holo_light.9.png ).
Sfortunatamente, dovrai creare copie locali di entrambe le immagini, anche se desideri personalizzare solo lo stato focalizzato . Questo perché textfield_search_default_holo_light
non è presente in R.drawable . Pertanto non è facilmente accessibile tramite @android:drawable/textfield_search_default_holo_light
, che potrebbe essere utilizzato nel selettore mostrato di seguito, invece di fare riferimento al drawable locale.
NOTA: stavo usando il tema Holo Light come base, ma puoi fare lo stesso con Holo Dark . Sembra che non ci sia alcuna reale differenza nelle 9 patch di stato selezionate tra i temi Chiaro e Scuro . Tuttavia, c'è una differenza in 9 patch per lo stato predefinito (vedi Chiaro vs Scuro ). Quindi, probabilmente non è necessario creare copie locali di 9 patch per lo stato selezionato , sia per i temi Dark che per quelli Light (supponendo che tu voglia gestirli entrambi e farli sembrare entrambi uguali a Holo Theme ). Basta fare una copia locale e usarla in formatoselettore disegnabile per entrambi i temi.
Ora, dovrai modificare le nove patch scaricate secondo le tue necessità (cioè cambiare il colore blu in rosso). Puoi dare un'occhiata al file usando lo strumento Draw 9-patch per verificare se è definito correttamente dopo la tua modifica.
Ho modificato i file usando GIMP con lo strumento matita da un pixel (abbastanza facile) ma probabilmente userete lo strumento da soli. Ecco la mia patch 9 personalizzata per lo stato focalizzato :
NOTA: per semplicità, ho utilizzato solo immagini per la densità mdpi . Dovrai creare 9 patch per più densità dello schermo se desideri il miglior risultato su qualsiasi dispositivo. Le immagini per Holo SearchView
possono essere trovate in mdpi , hdpi e xhdpi disegnabili.
Ora, dobbiamo creare un selettore disegnabile, in modo che l'immagine corretta venga visualizzata in base allo stato di visualizzazione. Crea file res/drawable/texfield_searchview_holo_light.xml
con il seguente contenuto:
<?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>
Useremo il disegnabile creato sopra per impostare lo sfondo per la LinearLayout
vista che contiene il campo di testo all'interno SearchView
- il suo ID è android:id/search_plate
. Quindi, ecco come farlo rapidamente nel codice, durante la creazione del menu delle opzioni:
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);
}
}
Effetto finale
Ecco lo screenshot del risultato finale:
Come ci sono arrivato
Penso che valga la pena conoscere come sono arrivato a questo, in modo che questo approccio possa essere utilizzato quando si personalizzano altre visualizzazioni.
Verifica del layout di visualizzazione
Ho controllato l' SearchView
aspetto del layout. Nel costruttore di SearchView si può trovare una linea che gonfia il layout:
inflater.inflate(R.layout.search_view, this, true);
Ora sappiamo che il SearchView
layout è nel file denominato res/layout/search_view.xml
. Esaminando search_view.xml possiamo trovare un LinearLayout
elemento interno (con id search_plate
) che ha android.widget.SearchView$SearchAutoComplete
al suo interno (sembra il nostro campo di testo della vista di ricerca):
<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">
Ora, ora che lo sfondo è impostato in base searchViewTextField
all'attributo del tema corrente .
Attributo investigativo (è facilmente impostabile?)
Per verificare come searchViewTextField
è impostato l'attributo, esaminiamo res / values / themes.xml . C'è un gruppo di attributi correlati a SearchView
in impostazione predefinita 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>
Vediamo che per il tema predefinito il valore è @drawable/textfield_searchview_holo_dark
. Anche il Theme.Light
valore è impostato in quel file .
Ora, sarebbe fantastico se questo attributo fosse accessibile tramite R.styleable , ma sfortunatamente non lo è. Per fare un confronto, Altri tema attributi che sono presenti sia in themes.xml e R.attr come textAppearance o selectableItemBackground . Se searchViewTextField
fosse presente in R.attr
(e R.stylable
) potremmo semplicemente usare il nostro selettore disegnabile quando definiamo il tema per l'intera nostra applicazione in XML. Per esempio:
<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>
Cosa dovrebbe essere modificato?
Ora sappiamo che dovremo accedere search_plate
tramite codice. Tuttavia, non sappiamo ancora come dovrebbe essere. In breve, cerchiamo i drawable usati come valori nei temi predefiniti: textfield_searchview_holo_dark.xml e textfield_searchview_holo_light.xml . Guardando il contenuto vediamo che il drawable fa selector
riferimento ad altri due drawable (che successivamente saranno 9 patch) in base allo stato di visualizzazione. Puoi trovare 9 patch estraibili aggregate da (quasi) tutte le versioni di Android su androiddrawables.com
Personalizzazione
Riconosciamo la linea blu in una delle 9 patch , quindi ne creiamo una copia locale e cambiamo i colori come desiderato.