J'essaie de changer le dessin qui se trouve dans le widget Android actionbar searchview.
Actuellement, cela ressemble à ceci:
mais je dois changer le fond bleu qui peut être dessiné en rouge.
J'ai essayé beaucoup de choses avant de lancer mon propre widget de recherche, mais rien ne semble fonctionner.
Quelqu'un peut-il m'indiquer dans la bonne direction pour changer cela?
Malheureusement, il n'y a aucun moyen de définir le style de champ de texte SearchView
à l'aide de thèmes, de styles et d'héritage dans XML comme vous vous pouvez utiliser l'arrière-plan d'éléments dans la liste déroulante ActionBar . En effet, 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 depuis les ressources XML (vous obtiendrez une erreur _No resource found that matches the given name: attr 'Android:searchViewTextField'
_).
Ainsi, la seule façon de substituer correctement le champ de texte SearchView
à l'arrière-plan est d'entrer dans ses éléments internes, d'obtenir un accès à la vue dont l'arrière-plan est basé sur searchViewTextField
et de définir le nôtre.
NOTE: La solution ci-dessous ne dépend que de l'id (_Android:id/search_plate
_) de l'élément dans SearchView
, il est donc plus indépendant de la version du SDK. que la traversée des enfants (par exemple, en utilisant searchView.getChildAt(0)
pour obtenir la vue correcte dans SearchView
), mais ce n’est pas à toute épreuve. Surtout si un fabricant décide de réimplémenter les éléments internes de SearchView
et que l'élément avec l'id mentionné ci-dessus n'est pas présent - le code ne fonctionnera pas.
Dans le Kit de développement logiciel (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 les images originales png dans le répertoire drawable-mdpi de référentiel Android git . 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 l'autre pour celui 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 focus. En effet, _textfield_search_default_holo_light
_ n'est pas présent dans R.drawable . Ainsi, il n'est pas facilement accessible via _@Android:drawable/textfield_search_default_holo_light
_, qui pourrait être utilisé dans le sélecteur présenté ci-dessous, au lieu de référencer localement.
NOTE: J'utilisais le thème [Holo Light, mais vous pouvez faire de même avec Holo Dark. Il semble qu'il n'y ait pas de réelle différence entre les thèmes état sélectionné 9-patchs entre les thèmes Clair et Sombre . Cependant, il y a une différence de 9 correctifs pour état par défaut (voir Clair vs Sombre ). Donc, il n’est probablement pas nécessaire de faire des copies locales de 9 correctifs pour état sélectionné, pour les deux thèmes Sombre et Clair (en supposant que vous souhaitiez pour gérer les deux, et les rendre les mêmes que dans Thème Holo). Créez simplement une copie locale et utilisez-la dans sélecteur pouvant être dessiné pour les deux thèmes.
Maintenant, vous devez éditer les neuf correctifs téléchargés selon vos besoins (c'est-à-dire changer la couleur bleue en rouge). Vous pouvez jeter un coup d'oeil au fichier en utilisant draw 9-patch tool pour vérifier s'il est correctement défini après votre modification.
J'ai édité des fichiers en utilisant GIMP avec un outil au crayon d'un pixel (assez facile), mais vous utiliserez probablement l'outil de votre choix. Voici mon correctif 9 personnalisé pour état ciblé:
REMARQUE: Par souci de simplicité, j'ai uniquement utilisé des images pour la densité mdpi. Vous devrez créer 9-patchs pour plusieurs densités d'écran si vous voulez obtenir le meilleur résultat sur n'importe quel appareil. Des images pour HoloSearchView
peuvent être trouvées dans mdpi , hdpi et xhdpi dessins.
Nous allons maintenant avoir besoin de créer un sélecteur pouvant être dessiné, de sorte que l'image appropriée soit affichée en fonction de l'état de la vue. Créez le 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 dessin que nous avons créé ci-dessus pour définir l’arrière-plan de la vue LinearLayout
qui contient un champ de texte dans SearchView
- son identifiant est _Android:id/search_plate
_. Voici comment procéder 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);
}
}
_
Voici la capture d'écran du résultat final:
Je pense que cela vaut la peine de dire comment je suis arrivé à cela, afin que cette approche puisse être utilisée lors de la personnalisation d'autres vues.
J'ai vérifié à quoi ressemble la mise en page de SearchView
. Dans constructeur SearchView on peut trouver une ligne qui gonfle la mise en page:
_inflater.inflate(R.layout.search_view, this, true);
_
Nous savons maintenant que la disposition SearchView
se trouve dans le fichier nommé _res/layout/search_view.xml
_. En regardant dans search_view.xml nous pouvons trouver un élément interne LinearLayout
(avec id _search_plate
_) qui contient _Android.widget.SearchView$SearchAutoComplete
_ (ressemble à notre champ de texte de la 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">
_
Nous savons maintenant que l'arrière-plan est défini en fonction de l'attribut searchViewTextField
du thème actuel.
Pour vérifier comment l'attribut searchViewTextField
est défini, nous étudions res/values / themes.xml . Il y a un groupe d'attributs lié à 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 _Theme.Light
_ value est également défini dans ce fichier .
Ce serait bien si cet attribut était accessible via R.styleable , mais, malheureusement, ce n’est pas le cas. Pour comparer, voir les autres attributs theme 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 pouvant être dessiné lors de la définition du thème de notre application entière 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>
_
Nous savons maintenant que nous devons accéder à _search_plate
_ par le code. Cependant, nous ne savons toujours pas à quoi cela devrait ressembler. En bref, nous recherchons les éléments de dessin 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 selector
, qui fait référence à deux autres tirables (qui sont plus tard des 9 correctifs) en fonction de l'état de la vue. Vous pouvez trouver des dessins cumulables de 9 correctifs de (presque) toutes les versions de Android sur androiddrawables.com)
Nous reconnaissons la ligne bleue dans l'un des 9 correctifs , nous en créons donc une copie locale et changeons de couleur selon les besoins.
Les solutions ci-dessus risquent de ne pas fonctionner si vous utilisez la bibliothèque appcompat. Vous devrez peut-être modifier le code pour le faire fonctionner pour la bibliothèque appcompat.
Voici la solution de travail pour la bibliothèque appcompat.
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.main_menu, menu);
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
MenuItem searchMenuItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchMenuItem);
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
SearchView.SearchAutoComplete searchAutoComplete = (SearchView.SearchAutoComplete)searchView.findViewById(Android.support.v7.appcompat.R.id.search_src_text);
searchAutoComplete.setHintTextColor(Color.WHITE);
searchAutoComplete.setTextColor(Color.WHITE);
View searchplate = (View)searchView.findViewById(Android.support.v7.appcompat.R.id.search_plate);
searchplate.setBackgroundResource(R.drawable.texfield_searchview_holo_light);
ImageView searchCloseIcon = (ImageView)searchView.findViewById(Android.support.v7.appcompat.R.id.search_close_btn);
searchCloseIcon.setImageResource(R.drawable.abc_ic_clear_normal);
ImageView voiceIcon = (ImageView)searchView.findViewById(Android.support.v7.appcompat.R.id.search_voice_btn);
voiceIcon.setImageResource(R.drawable.abc_ic_voice_search);
ImageView searchIcon = (ImageView)searchView.findViewById(Android.support.v7.appcompat.R.id.search_mag_icon);
searchIcon.setImageResource(R.drawable.abc_ic_search);
return super.onCreateOptionsMenu(menu);
}
Votre méthode onCreateOptionsMenu
doit être:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.option, menu);
SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
int linlayId = getResources().getIdentifier("Android:id/search_plate", null, null);
ViewGroup v = (ViewGroup) searchView.findViewById(linlayId);
v.setBackgroundResource(R.drawable.searchviewredversion);
return super.onCreateOptionsMenu(menu);
}
où votre recherche est menu_search
bien sur
et voici le searchviewredversion
(celui-ci est la version xhdpi): http://img836.imageshack.us/img836/5964/searchviewredversion.png
La solution ci-dessus ne fonctionne pas avec ActionBarSherlock 4.2. Par conséquent, elle n'est pas rétrocompatible avec Android 2.x.)
public static void styleSearchView(SearchView searchView, Context context) {
View searchPlate = searchView.findViewById(R.id.abs__search_plate);
searchPlate.setBackgroundResource(R.drawable.your_custom_drawable);
AutoCompleteTextView searchText = (AutoCompleteTextView) searchView.findViewById(R.id.abs__search_src_text);
searchText.setHintTextColor(context.getResources().getColor(R.color.your_custom_color));
}
Je suis fatigué de le faire aussi et j'utilise v7. L’application s’est écrasée lorsque j’ai essayé de récupérer le searchPlate
via le getIdentifier()
, donc je l’ai fait de cette façon:
View searchPlate = searchView.findViewById(Android.support.v7.appcompat.R.id.search_plate);
J'ai également rencontré le même problème. J'ai utilisé la bibliothèque appcompat v7 et défini un style personnalisé. Dans le dossier drawable, mettez le fichier bottom_border.xml qui ressemble à ceci:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:Android="http://schemas.Android.com/apk/res/Android" >
<item>
<shape >
<solid Android:color="@color/blue_color" />
</shape>
</item>
<item Android:bottom="0.8dp"
Android:left="0.8dp"
Android:right="0.8dp">
<shape >
<solid Android:color="@color/background_color" />
</shape>
</item>
<!-- draw another block to cut-off the left and right bars -->
<item Android:bottom="2.0dp">
<shape >
<solid Android:color="@color/main_accent" />
</shape>
</item>
</layer-list>
Dans le dossier de valeurs styles_myactionbartheme.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppnewTheme" parent="Theme.AppCompat.Light">
<item name="Android:windowBackground">@color/background</item>
<item name="Android:actionBarStyle">@style/ActionBar</item>
<item name="Android:actionBarWidgetTheme">@style/ActionBarWidget</item>
</style>
<!-- Actionbar Theme -->
<style name="ActionBar" parent="Widget.AppCompat.Light.ActionBar.Solid.Inverse">
<item name="Android:background">@color/main_accent</item>
<!-- <item name="Android:icon">@drawable/abc_ic_ab_back_holo_light</item> -->
</style>
<style name="ActionBarWidget" parent="Theme.AppCompat.Light">
<!-- SearchView customization-->
<!-- Changing the small search icon when the view is expanded -->
<!-- <item name="searchViewSearchIcon">@drawable/ic_action_search</item> -->
<!-- Changing the cross icon to erase typed text -->
<!-- <item name="searchViewCloseIcon">@drawable/ic_action_remove</item> -->
<!-- Styling the background of the text field, i.e. blue bracket -->
<item name="searchViewTextField">@drawable/bottom_border</item>
<!-- Styling the text view that displays the typed text query -->
<item name="searchViewAutoCompleteTextView">@style/AutoCompleteTextView</item>
</style>
<style name="AutoCompleteTextView" parent="Widget.AppCompat.Light.AutoCompleteTextView">
<item name="Android:textColor">@color/text_color</item>
<!-- <item name="Android:textCursorDrawable">@null</item> -->
<!-- <item name="Android:textColorHighlight">@color/search_view_selected_text</item> -->
</style>
</resources>
J'ai défini le fichier custommenu.xml pour l'affichage du menu:
<menu xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:com.example.actionbartheme="http://schemas.Android.com/apk/res-auto" >
<item Android:id="@+id/search"
Android:title="@string/search_title"
Android:icon="@drawable/search_buttonn"
com.example.actionbartheme:showAsAction="ifRoom|collapseActionView"
com.example.actionbartheme:actionViewClass="Android.support.v7.widget.SearchView"/>
Votre activité doit étendre ActionBarActivity au lieu d’Activity.
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.custommenu, menu);
}
Dans le fichier manifeste:
<application
Android:allowBackup="true"
Android:icon="@drawable/ic_launcher"
Android:label="@string/app_name"
Android:theme="@style/AppnewTheme" >
Pour plus d'informations, voir ici:
Here http://www.jayway.com/2014/06/02/Android-theming-the-actionbar/
Commençons par créer un fichier XML appelé search_widget_background.xml, à utiliser comme dessin, c’est-à-dire sous le répertoire drawable.
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:shape="rectangle" >
<solid Android:color="@color/red" />
</shape>
Ce dessinable sera utilisé comme arrière-plan pour notre widget de recherche. J'ai défini la couleur sur rouge parce que c'est ce que vous avez demandé, mais vous pouvez la définir sur n'importe quelle couleur définie par la balise @color. Vous pouvez même le modifier davantage en utilisant les attributs définis pour balise shape (créer des coins arrondis, créer un fond ovale, etc.).
L'étape suivante consiste à définir l'arrière-plan de notre widget de recherche sur celui-ci. Ceci peut être accompli de la manière suivante:
public boolean onCreateOptionsMenu(Menu menu) {
SearchView searchView = (SearchView)menu.findItem(R.id.my_search_view).getActionView();
Drawable d = getResources().getDrawable(R.drawable.search_widget_background);
searchView.setBackground(d);
...
}
Mise à jour
Si vous utilisez AndroidX, vous pouvez le faire comme ceci
View searchPlate = svSearch. findViewById(androidx.appcompat.R.id.search_plate);
if (searchPlate != null) {
AutoCompleteTextView searchText = searchPlate.findViewById(androidx.appcompat.R.id.search_src_text);
if (searchText != null){
searchText.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimension(R.dimen.edittext_text_size));
searchText.setMaxLines(1);
searchText.setSingleLine(true);
searchText.setTextColor(getResources().getColor(R.color.etTextColor));
searchText.setHintTextColor(getResources().getColor(R.color.etHintColor));
searchText.setBackground(null);
}
}
public boolean onCreateOptionsMenu(Menu menu) {
........
// Set the search plate color
int linlayId = getResources().getIdentifier("Android:id/search_plate", null, null);
View view = searchView.findViewById(linlayId);
Drawable drawColor = getResources().getDrawable(R.drawable.searchcolor);
view.setBackground( drawColor );
........
}
et c'est le fichier searchablecolor.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:Android="http://schemas.Android.com/apk/res/Android" >
<item>
<shape >
<solid Android:color="#ffffff" />
</shape>
</item>
<!-- main color -->
<item Android:bottom="1.5dp"
Android:left="1.5dp"
Android:right="1.5dp">
<shape >
<solid Android:color="#2c4d8e" />
</shape>
</item>
<!-- draw another block to cut-off the left and right bars -->
<item Android:bottom="18.0dp">
<shape >
<solid Android:color="#2c4d8e" />
</shape>
</item>
</layer-list>
J'ai expliqué à la fin de ce post avec des images que cela s'applique aux formes xamarin. Mais je pense que vous pouvez le comprendre, car il est basé sur le code source de searchview d’Android
Comment changer l'image du bouton d'annulation de la barre de recherche dans les formulaires xamarin
Si vous gonflez Searchview comme ceci: "getMenuInflater () .flate (R.menu.search_menu, menu);". Ensuite, vous pouvez personnaliser cette recherche via style.xml comme ci-dessous.
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="searchViewStyle">@style/SearchView.ActionBar</item>
</style>
<style name="SearchView.ActionBar" parent="Widget.AppCompat.SearchView.ActionBar">
<item name="queryBackground">@drawable/drw_search_view_bg</item>
<item name="searchHintIcon">@null</item>
<item name="submitBackground">@null</item>
<item name="closeIcon">@drawable/vd_cancel</item>
<item name="searchIcon">@drawable/vd_search</item>
</style>