126 votes

Modification de l'arrière-plan du widget searchview

J'essaie de modifier le dessinable qui se trouve dans le widget searchview de la barre d'action Android.

Actuellement, cela ressemble à ceci : enter image description here

mais j'ai besoin de changer l'arrière-plan bleu du dessinable en une couleur rouge.

J'ai essayé de nombreuses choses, à part créer mon propre widget de recherche, mais rien ne semble fonctionner.

Quelqu'un peut-il m'indiquer la bonne direction pour changer cela ?

1 votes

Je crois ce poste SO peut vous aider dans ce que vous voulez accomplir, si vous ne l'avez pas déjà consulté.

0 votes

@Angelo Malheureusement, ceci n'est pas possible avec SearchView fond parce qu'il n'est pas disponible par l'intermédiaire de R.styleable . Ma réponse ci-dessous décrit comment le faire en code.

0 votes

Comment avez-vous obtenu le texte "Enter film name" ?

259voto

vArDo Points 3428

Intro

Malheureusement, il n'y a aucun moyen de définir SearchView le style des champs de texte à l'aide de thèmes, de styles et de l'héritage en XML, comme vous le souhaitez peut faire avec l'arrière-plan des éléments dans le dropdown de la barre d'action . Cela s'explique par le fait que selectableItemBackground est listé comme pouvant être stylé en R.stylable alors que searchViewTextField (attribut du 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 un message d'erreur No resource found that matches the given name: attr 'android:searchViewTextField' erreur).

Définir l'arrière-plan du champ de texte SearchView à partir du code

Donc, la seule façon de substituer correctement le fond d'écran de SearchView est d'entrer dans son fonctionnement interne, d'obtenir l'accès à une vue dont l'arrière-plan est défini sur la base de l'arrière-plan du champ de texte. searchViewTextField et de fixer les nôtres.

NOTE : La solution ci-dessous ne dépend que de l'id ( android:id/search_plate ) de l'élément dans SearchView Il s'agit donc d'une méthode plus indépendante de la version du SDK que la traversée des enfants (par exemple, en utilisant la fonction searchView.getChildAt(0) pour arriver à la bonne vue dans SearchView ), mais ce n'est pas à l'épreuve des balles. En particulier si un fabricant décide de réimplémenter des éléments internes de SearchView 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 la zone SearchView est déclaré par le biais de neuf pattes alors on va faire de même. Vous pouvez trouver l'original png images en drawable-mdpi répertoire de Dépôt git Android . Nous sommes intéressés par deux images. L'une pour l'état lorsque le champ de texte est sélectionné (nommée textfield_search_selected_holo_light.9.png ) et un autre pour les endroits 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 ne souhaitez personnaliser que l'image de l'entreprise. ciblé l'état. Cela s'explique par le fait que textfield_search_default_holo_light n'est pas présent dans R.drawable . Il n'est donc pas facilement accessible par @android:drawable/textfield_search_default_holo_light qui pourrait être utilisé dans le sélecteur ci-dessous, au lieu de faire référence à la drawable locale.

NOTE : J'utilisais Holo Light comme base, mais vous pouvez faire la même chose avec Holo Dark . Il semble qu'il n'y ait pas de réelle différence dans état sélectionné 9-patchs entre Lumière y Dark thèmes. Cependant, il y a une différence dans les 9-patches pour état par défaut (voir Lumière vs Dark ). Ainsi, il n'est probablement pas nécessaire de faire des copies locales de 9-patches pour état sélectionné pour les deux Dark y Lumière (en supposant que vous souhaitiez les gérer tous les deux et leur donner la même apparence qu'en Thème Holo ). Il suffit de faire une copie locale et de l'utiliser dans sélectionnable pour les deux thèmes.

Maintenant, vous devez modifier les neuf patchs téléchargés selon vos besoins (par exemple, changer la couleur bleue en rouge). Vous pouvez jeter un coup d'oeil au fichier en utilisant dessiner l'outil 9-patch pour vérifier s'il est correctement défini après votre modification.

J'ai édité des fichiers en utilisant GIMP avec l'outil crayon à un pixel (assez facile) mais vous utiliserez probablement l'outil de votre choix. Voici mon 9-patch personnalisé pour état ciblé :

enter image description here

NOTE : Pour simplifier, j'ai utilisé uniquement des images pour mdpi densité. 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. Images pour Holo SearchView peuvent être trouvés dans mdpi , hdpi y xhdpi traçable.

Maintenant, nous devons créer un sélecteur drawable, afin que l'image appropriée soit affichée en fonction de l'état de la vue. Créer 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 la table de dessin créée ci-dessus pour définir l'arrière-plan de la table de dessin. LinearLayout qui contient un champ de texte dans SearchView - son identifiant est android:id/search_plate . Voici donc comment faire cela rapidement en 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 :

enter image description here

Comment j'en suis arrivé là

Je pense que cela vaut la peine de mentionner comment j'en suis arrivé là, afin que cette approche puisse être utilisée lors de la personnalisation d'autres vues.

Vérification de la disposition des vues

J'ai vérifié comment SearchView la disposition ressemble. Sur Contructeur SearchView on peut trouver une ligne qui gonfle la mise en page :

inflater.inflate(R.layout.search_view, this, true);

Nous savons maintenant que SearchView est dans un fichier nommé res/layout/search_view.xml . En regardant dans vue_de_recherche.xml nous pouvons trouver un LinearLayout (avec l'id search_plate ) qui a android.widget.SearchView$SearchAutoComplete à l'intérieur (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">

Maintenant, nous savons que l'arrière-plan est défini sur la base du thème actuel. searchViewTextField attribut.

Recherche d'un attribut (est-il facilement paramétrable ?)

Pour vérifier comment searchViewTextField est défini, nous examinons res/values/themes.xml . Il y a 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 Theme.Light valeur est également défini dans ce fichier .

Maintenant, ce serait bien si cet attribut était accessible par le biais de R.stylisable mais, malheureusement, ce n'est pas le cas. Pour comparaison, voir d'autres thème qui sont présents à la fois dans thèmes.xml y R.attr comme apparence du texte o selectableItemBackground . Si searchViewTextField était présent dans R.attr (y R.stylable ), nous pourrions simplement utiliser notre sélecteur drawable lors de la définition du thème de l'ensemble de 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>

Qu'est-ce qui doit être modifié ?

Maintenant nous savons, que nous devrons accéder search_plate par le biais du 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 y textfield_searchview_holo_light.xml . En regardant le contenu, nous voyons que le drawable est selector qui font référence à deux autres objets dessinés (qui deviendront plus tard des "9-patches") en fonction de l'état de la vue. Vous pouvez trouver des graphiques 9-patchs agrégés pour (presque) toutes les versions d'Android à l'adresse suivante androiddrawables.com

Personnalisation de

Nous reconnaissons la ligne bleue dans une des 9 pièces Nous créons donc une copie locale et changeons les couleurs comme nous le souhaitons.

0 votes

Votre code java ne fonctionnera pas, son SearchView est dans l'ActionBar et ne peut pas être trouvé avec la méthode findViewById. Mais le reste est correct !

0 votes

@VinceFR Merci de le signaler. Je ne l'avais pas remarqué (je me suis concentré sur SearchView lui-même). Puis-je fusionner votre réponse (remplacer onCreateOptionsMenu) avec la mienne ?

0 votes

@VinceFR J'ai déplacé mon code à partir de onCreate() pour onCreateOptionsMenu() comme vous l'avez suggéré. J'ai voté pour votre réponse.

33voto

Abdul Rahman Points 187

Les solutions ci-dessus peuvent ne pas fonctionner si vous utilisez la bibliothèque appcompat. Vous devrez peut-être modifier le code pour qu'il fonctionne avec la bibliothèque appcompat.

Voici la solution fonctionnelle 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);
}

1 votes

Cela ne fonctionne pas pour le search_mag_icon. Cela donne "Style contains key with bad entry : 0x01010479"

1 votes

La plaque de recherche ne fonctionne pas pour moi (elle fait quelque chose mais je ne vois pas de changement à la ligne de fond), mais l'idée générale pour AppCompat est très utile

14voto

VinceFR Points 1693

Votre 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ù se trouve votre objet de recherche menu_search hors des sentiers battus

et voici le searchviewredversion (celle-ci est la version xhdpi) : http://img836.imageshack.us/img836/5964/searchviewredversion.png

enter image description here

0 votes

Existe-t-il un moyen de modifier l'icône de recherche et le bouton de fermeture de la même manière ?

0 votes

Je ne sais pas pour la SherlockActionBar 4.2 mais oui, vous pouvez changer l'icône de recherche et le bouton de fermeture de la même manière !

0 votes

ActionbarSherlock possède ses propres thèmes et définit son propre SearchView. Cela signifie que vous pouvez simplement ajouter un élément à votre thème nommé searchViewTextField et utiliser la définition du drawable et les 9 patches ci-dessus.

13voto

Destil Points 3673

La solution ci-dessus ne fonctionne pas avec ActionBarSherlock 4.2 et n'est donc pas rétrocompatible avec Android 2.x. Voici un code fonctionnel qui configure l'arrière-plan de SearchView et le texte de l'indice sur ActionBarSherlock 4.2 :

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));
}

0 votes

Où dois-je mettre ce code ? j'essaie de faire cela dans la version 4.2 de la barre d'action. ma question stackoverflow.com/questions/13992424/

0 votes

Bonjour, appelez-le depuis la méthode onCreateOptionsMenu. Trouvez searchView et passez-le à cette méthode.

0 votes

Merci. Savez-vous comment supprimer le symbole Mag en ligne, comme indiqué ici ? i.imgur.com/YvBz2.png

3voto

Suhas Patil Points 66

J'ai également rencontré le même problème. J'ai utilisé la bibliothèque appcompat v7 et défini un style personnalisé pour celle-ci. Dans le dossier drawable, j'ai placé 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 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é devrait étendre ActionBarActivity au lieu de 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 :
Aquí http://www.jayway.com/2014/06/02/Android-theming-the-actionbar/

0 votes

Vérifiez : stackoverflow.com/questions/8211929/ pour un autre exemple de LayerList.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X