Intro
Malheureusement, il n'y a aucun moyen de définir SearchViewle style de champ de texte à l'aide de thèmes, de styles et d'héritage en XML comme vous pouvez le faire avec l'arrière-plan des éléments dans la liste déroulante ActionBar . En effet, il selectableItemBackground est répertorié comme pouvant être stylisé dans R.stylable, alors que searchViewTextField(attribut de thème qui nous intéresse) ne l'est pas. Ainsi, nous ne pouvons pas y accéder facilement à partir des ressources XML (vous obtiendrez une No resource found that matches the given name: attr 'android:searchViewTextField'erreur).
Définition de l'arrière-plan du champ de texte SearchView à partir du code
Ainsi, la seule façon de remplacer correctement l'arrière-plan du SearchViewchamp de texte est d'entrer dans ses éléments internes, d'acquérir un accès à une vue qui a un arrière-plan basé sur searchViewTextFieldet de définir le nôtre.
REMARQUE: La solution ci-dessous ne dépend que de l'id ( android:id/search_plate) de l'élément à l'intérieur SearchView, donc c'est plus indépendant de la version du SDK que le parcours des enfants (par exemple, utiliser searchView.getChildAt(0)pour obtenir la bonne vue SearchView), mais ce n'est pas à l'épreuve des balles. Surtout si un fabricant décide de réimplémenter les internes deSearchView et l'élément avec l'ID mentionné ci-dessus n'est pas présent - le code ne fonctionnera pas.
Dans le SDK, l'arrière-plan du champ de texte dans SearchViewest déclaré via neuf correctifs , nous allons donc procéder de la même manière. Vous pouvez trouver des images png originales dans le répertoire drawable-mdpi du référentiel git Android . Nous sommes intéressés par deux images. Un pour l'état lorsque le champ de texte est sélectionné (nommé textfield_search_selected_holo_light.9.png ) et un pour l'endroit où il ne l'est pas (nommé textfield_search_default_holo_light.9.png ).
Malheureusement, vous devrez créer des copies locales des deux images, même si vous souhaitez personnaliser uniquement l' état ciblé . C'est parce que textfield_search_default_holo_lightn'est pas présent dans R.drawable . Il n'est donc pas facilement accessible via @android:drawable/textfield_search_default_holo_light, qui pourrait être utilisé dans le sélecteur illustré ci-dessous, au lieu de référencer local drawable.
REMARQUE: J'utilisais le thème Holo Light comme base, mais vous pouvez faire de même avec Holo Dark . Il semble qu'il n'y ait pas de réelle différence dans les 9 patches d' état sélectionnés entre les thèmes clairs et sombres . Cependant, il y a une différence entre les 9 correctifs pour l' état par défaut (voir Clair vs foncé ). Ainsi, il n'est probablement pas nécessaire de créer des copies locales de 9 correctifs pour l' état sélectionné , pour les thèmes sombres et clairs (en supposant que vous souhaitiez gérer les deux et les rendre tous les deux identiques à ceux du sélecteur de thème Holo ). Faites simplement une copie locale et utilisez-la danspouvant être dessiné pour les deux thèmes.
Maintenant, vous devrez modifier les neuf patchs téléchargés selon vos besoins (c'est-à-dire changer la couleur bleue en rouge). Vous pouvez jeter un œil au fichier à l'aide de l' outil draw 9-patch pour vérifier s'il est correctement défini après votre modification.
J'ai édité des fichiers à l'aide de GIMP avec l'outil crayon d'un pixel (assez facile) mais vous utiliserez probablement votre propre outil. Voici mon 9-patch personnalisé pour l' état ciblé :

REMARQUE: par souci de simplicité, je n'ai utilisé que des images pour une densité mdpi . Vous devrez créer 9 patchs pour plusieurs densités d'écran si vous voulez le meilleur résultat sur n'importe quel appareil. Les images pour Holo SearchView peuvent être trouvées dans mdpi , hdpi et xhdpi drawable.
Maintenant, nous devrons créer un sélecteur dessinable, afin que l'image appropriée soit affichée en fonction de l'état d'affichage. Créez un fichier res/drawable/texfield_searchview_holo_light.xmlavec le contenu suivant:
<?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>
Nous utiliserons le dessinable créé ci-dessus pour définir l'arrière-plan de la LinearLayoutvue contenant un champ de texte SearchView- son identifiant est android:id/search_plate. Alors, voici comment faire cela rapidement dans le code, lors de la création du menu d'options:
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);
}
}
Effet final
Voici la capture d'écran du résultat final:

Comment j'y suis arrivé
Je pense que cela vaut la peine de savoir comment j'y suis arrivé, afin que cette approche puisse être utilisée lors de la personnalisation d'autres vues.
Vérification de la disposition de la vue
J'ai vérifié à quoi SearchViewressemble la mise en page. Dans SearchView contructor, on peut trouver une ligne qui gonfle la mise en page:
inflater.inflate(R.layout.search_view, this, true);
Maintenant, nous savons que la SearchViewmise en page est dans le fichier nommé res/layout/search_view.xml. En regardant search_view.xml, nous pouvons trouver un LinearLayoutélément interne (avec id search_plate) qui contient à l' android.widget.SearchView$SearchAutoCompleteintérieur (ressemble à notre champ de texte de vue de recherche):
<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">
Maintenant, nous avons maintenant que l'arrière-plan est défini en fonction de l' searchViewTextFieldattribut du thème actuel .
Attribut d'enquête (est-il facilement paramétrable?)
Pour vérifier comment l' searchViewTextFieldattribut est défini, nous examinons res / values / themes.xml . Il existe un groupe d'attributs liés à SearchViewpar défaut 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>
Nous voyons que pour le thème par défaut, la valeur est @drawable/textfield_searchview_holo_dark. Pour la Theme.Lightvaleur est également définie dans ce fichier .
Maintenant, ce serait génial si cet attribut était accessible via R.styleable , mais malheureusement ce n'est pas le cas. A titre de comparaison, voir d' autres thèmes attributs qui sont présents à la fois dans themes.xml et R.attr comme textAppearance ou selectableItemBackground . Si searchViewTextFieldétait présent dans R.attr(et R.stylable), nous pourrions simplement utiliser notre sélecteur dessinable lors de la définition du thème pour toute notre application en XML. Par exemple:
<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>
Que faut-il modifier?
Maintenant, nous savons que nous devrons accéder search_platepar code. Cependant, nous ne savons toujours pas à quoi cela devrait ressembler. En bref, nous recherchons les drawables utilisés comme valeurs dans les thèmes par défaut: textfield_searchview_holo_dark.xml et textfield_searchview_holo_light.xml . En regardant le contenu, nous voyons que le dessinable est celui selectorqui fait référence à deux autres dessinables (qui se trouvent être 9 patches plus tard) en fonction de l'état d'affichage. Vous pouvez trouver des tirables agrégés à 9 patchs de (presque) toutes les versions d'Android sur androiddrawables.com
Personnalisation
Nous reconnaissons la ligne bleue dans l' un des 9 patchs , nous en créons donc une copie locale et changeons les couleurs à votre guise.