Intro
Malheureusement, il n'y a aucun moyen de définir SearchView
le 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 SearchView
champ 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 searchViewTextField
et 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 SearchView
est 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_light
n'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.xml
avec 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 LinearLayout
vue 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 SearchView
ressemble 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 SearchView
mise 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$SearchAutoComplete
inté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' searchViewTextField
attribut du thème actuel .
Attribut d'enquête (est-il facilement paramétrable?)
Pour vérifier comment l' searchViewTextField
attribut est défini, nous examinons res / values / themes.xml . Il existe un groupe d'attributs liés à SearchView
par 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.Light
valeur 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_plate
par 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 selector
qui 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.