web-dev-qa-db-fra.com

Modification de l'arrière-plan pouvant être dessiné du widget searchview

J'essaie de changer le dessin qui se trouve dans le widget Android actionbar searchview.

Actuellement, cela ressemble à ceci: enter image description here

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?

120
Martyn

Intro

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, selectableItemBackgroundest 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'_).

Définition du fond de champ de texte SearchView à partir du code

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é:

enter image description here

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

}
_

Effet final

Voici la capture d'écran du résultat final:

enter image description here

Comment je suis arrivé à ça

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.

Vérification de la disposition de la vue

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.

Attribut d'investigation (est-il facilement paramétrable?)

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>
_

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

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)

Personnalisation

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.

251
vArDo

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);
}
31
Abdul Rahman

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

enter image description here

14
VinceFR

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));
}
13
David Vávra

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);
5
Ido

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/

3
Suhas Patil

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);
...
    }
2
Erol

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);
        }
    }
1
Secret Coder
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>
1
M.Raheel

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

0
vu ledang

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>
0
E Player Plus