web-dev-qa-db-fra.com

Comment changer l'icône par défaut sur le SearchView, à utiliser dans la barre d'action sous Android?

J'ai de la difficulté à personnaliser l'icône de recherche dans SearchView. De mon point de vue, l'icône peut être modifiée dans les attributs de l'élément, non? Il suffit de vérifier le code ci-dessous ..

Est-ce que quelqu'un peut me dire ce que je fais mal? 

C'est le menu que j'utilise, avec mon icône de recherche personnalisée icn_lupa . Mais quand je lance l'application, j'obtiens toujours l'icône de recherche par défaut ...

<menu xmlns:Android="http://schemas.Android.com/apk/res/Android">
<item Android:id="@+id/menu_search"
      Android:title="@string/menu_search"
      Android:icon="@drawable/icn_lupa"
      Android:showAsAction="always"
      Android:actionViewClass="Android.widget.SearchView" />
</menu>

Merci d'avance.

51
Valdemar

Il semble que actionViewClass se trouve au-dessus de l’icône et il ne semble pas que vous puissiez le changer depuis cette classe .

Vous avez deux solutions:

4
Snicolas

J'ai trouvé un autre moyen de changer l'icône de recherche qui va dans le même sens que la réponse de Diego Pino mais directement dans onPrepareOptionsMenu.

Dans votre menu.xml (comme avant)

<menu xmlns:Android="http://schemas.Android.com/apk/res/Android">
<item Android:id="@+id/action_search"
      Android:icon="@drawable/ic_action_fav"
      Android:title="@string/action_websearch"
      Android:showAsAction="always|never"
      Android:actionViewClass="Android.widget.SearchView" />
</menu>

Dans votre activité:

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    MenuItem searchViewMenuItem = menu.findItem(R.id.action_search);    
    mSearchView = (SearchView) searchViewMenuItem.getActionView();
    int searchImgId = getResources().getIdentifier("Android:id/search_button", null, null);
    ImageView v = (ImageView) mSearchView.findViewById(searchImgId);
    v.setImageResource(R.drawable.your_new_icon); 
    mSearchView.setOnQueryTextListener(this);
    return super.onPrepareOptionsMenu(menu);
}

J'ai suivi l'exemple pour changer le edittext dans ce exemple .

Vous devriez pouvoir le faire pour tous les icônes/fonds de votre SearchView. Pour trouver le bon ID, vous pouvez vérifier ici .

J'espère que cela aide aussi quelqu'un d'autre!

UPDATE Novembre 2017:

Depuis cette réponse, Android a été mis à jour avec la possibilité de changer l'icône de recherche via XML. 

Si vous ciblez quelque chose sous Android v21, vous pouvez utiliser: 

<Android.support.v7.widget.SearchView
    Android:layout_width="wrap_content"
    Android:layout_height="match_parent"
    app:searchIcon="@drawable/ic_search_white_24dp"
    app:closeIcon="@drawable/ic_clear_white_24dp" />

Ou v21 et plus tard:

<SearchView
    Android:layout_width="wrap_content"
    Android:layout_height="match_parent"
    Android:searchIcon="@drawable/ic_search_white_24dp"
    Android:closeIcon="@drawable/ic_clear_white_24dp" />

Et il y a encore plus d'options:

closeIcon
commitIcon
goIcon
searchHintIcon
searchIcon
voiceIcon
84
just_user

Belle réponse de @just_user

Pour mon cas, comme je me sers de la bibliothèque appcompat v7 pour le SearchView + ActionBar, j’ai un peu modifié sa solution pour la rendre compatible avec mon projet, elle devrait fonctionner si tant que vous n’avez rien modifié bibliothèque

XML:

<menu xmlns:Android="http://schemas.Android.com/apk/res/Android"
      xmlns:metrodeal="http://schemas.Android.com/apk/res-auto" >


    <item
        Android:id="@+id/main_menu_action_search"
        Android:orderInCategory="100"
        Android:title="@string/search"
        metrodeal:showAsAction="always"
        metrodeal:actionViewClass="Android.support.v7.widget.SearchView" 
        Android:icon="@drawable/search_btn"/>

</menu>

Code Java:

@Override
public void onPrepareOptionsMenu(Menu menu) {
    MenuItem searchViewMenuItem = menu.findItem(R.id.main_menu_action_search);
    SearchView mSearchView = (SearchView) MenuItemCompat.getActionView(searchViewMenuItem);
    int searchImgId = Android.support.v7.appcompat.R.id.search_button; // I used the explicit layout ID of searchview's ImageView
    ImageView v = (ImageView) mSearchView.findViewById(searchImgId);
    v.setImageResource(R.drawable.search_btn);
    super.onPrepareOptionsMenu(menu);
}

Excuse pour la très grande icône (je n’ai pas encore redimensionné l’icône), mais cela devrait fonctionner tel quel.

enter image description here

36
patrickjason91

Je me débattais aussi avec ce problème, mais j’ai utilisé accidentellement 'collapseActionView' et cela a été corrigé! Mon menu.xml ressemble à ceci:

<menu xmlns:Android="http://schemas.Android.com/apk/res/Android">
<item Android:id="@+id/menu_search"
      Android:title="@string/menu_search"
      Android:showAsAction="always|withText|collapseActionView"
      Android:actionViewClass="Android.widget.SearchView"
      Android:icon="@Android:drawable/ic_menu_search" /> 
</menu>

L'inconvénient est que, sur les tablettes, SearchView apparaîtra dans la partie gauche de la barre d'actions au lieu de l'emplacement où se trouve l'icône de recherche, mais cela ne me dérange pas.

17
Mathieu Post

J'ai défini un style pour le faire.

voici mon xml:

  <Android.support.v7.widget.SearchView
        Android:id="@+id/sv_search"
        Android:icon="@Android:drawable/ic_menu_search"
        Android:layout_width="fill_parent"
        **style="@style/CitySearchView"**
        Android:layout_height="wrap_content"/>

et c'est mon style:

<style name="CitySearchView" parent="Base.Widget.AppCompat.SearchView">
    <item name="searchIcon">@drawable/ic_more_search</item>
</style>

Que c'est

Après avoir terminé, jetez simplement un coup d’œil à Base.Widget.AppCompat.SearchView.

<style name="Base.Widget.AppCompat.SearchView" parent="Android:Widget">
    <item name="layout">@layout/abc_search_view</item>
    <item name="queryBackground">@drawable/abc_textfield_search_material</item>
    <item name="submitBackground">@drawable/abc_textfield_search_material</item>
    <item name="closeIcon">@drawable/abc_ic_clear_mtrl_alpha</item>
    <item name="searchIcon">@drawable/abc_ic_search_api_mtrl_alpha</item>
    <item name="goIcon">@drawable/abc_ic_go_search_api_mtrl_alpha</item>
    <item name="voiceIcon">@drawable/abc_ic_voice_search_api_mtrl_alpha</item>
    <item name="commitIcon">@drawable/abc_ic_commit_search_api_mtrl_alpha</item>
    <item name="suggestionRowLayout">@layout/abc_search_dropdown_item_icons_2line</item>
</style>

chaque élément peut être remplacé en définissant un nouveau style.

J'espère que ça aide!

14
woodyhou

Il y a un moyen de faire ça. L'astuce consiste à récupérer ImageView à l'aide de son identifiant et à définir une nouvelle image avec setImageResource(). Cette solution est inspirée de Modification de l’arrière-plan dessinable du widget searchview .

private SearchView searchbox;

private void customizeSearchbox() {
    setSearchHintIcon(R.drawable.new_search_icon);
}

private void setSearchHintIcon(int resourceId) {
    ImageView searchHintIcon = (ImageView) findViewById(searchbox, 
        "Android:id/search_mag_icon");
    searchHintIcon.setImageResource(resourceId);
}

private View findViewById(View v, String id) {
    return v.findViewById(v.getContext().getResources().
        getIdentifier(id, null, null));        
}
13
Diego Pino

SearchView searchView = (SearchView) findViewById (R.id.address_search);

    try {
        Field searchField = SearchView.class
                .getDeclaredField("mSearchButton");
        searchField.setAccessible(true);
        ImageView searchBtn = (ImageView) searchField.get(searchView);
        searchBtn.setImageResource(R.drawable.search_glass);
    } catch (NoSuchFieldException e) {
    } catch (IllegalAccessException e) {
    }
6
SumeetP

Après quelques recherches, j'ai trouvé la solution ici . Le truc, c'est que l'icône ne se trouve pas dans une ImageView mais dans un objet Spannable.

// Accessing the SearchAutoComplete
int queryTextViewId = getResources().getIdentifier("Android:id/search_src_text", null, null);  
View autoComplete = searchView.findViewById(queryTextViewId);

Class<?> clazz = Class.forName("Android.widget.SearchView$SearchAutoComplete");

SpannableStringBuilder stopHint = new SpannableStringBuilder("   ");  
stopHint.append(getString(R.string.your_new_text));

// Add the icon as an spannable
Drawable searchIcon = getResources().getDrawable(R.drawable.ic_action_search);  
Method textSizeMethod = clazz.getMethod("getTextSize");  
Float rawTextSize = (Float)textSizeMethod.invoke(autoComplete);  
int textSize = (int) (rawTextSize * 1.25);  
searchIcon.setBounds(0, 0, textSize, textSize);  
stopHint.setSpan(new ImageSpan(searchIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

// Set the new hint text
Method setHintMethod = clazz.getMethod("setHint", CharSequence.class);  
setHintMethod.invoke(autoComplete, stopHint);
5
znat
<SearchView
            Android:searchIcon="@drawable/ic_action_search"
..../>

utiliser la balise XML searchIcon

2
TomTaila

Astuce de mise à jour d'AutocompleteTextView pour la mise à jour de l'icône de recherche en mode développé, copiée à partir de la source Android, 

@Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        mSearchMenuItem = menu.findItem(R.id.action_search);
        SearchView searchView = (SearchView) mSearchMenuItem.getActionView();
        int searchImgId = getResources().getIdentifier("Android:id/search_button", null, null);
        ImageView v = (ImageView) searchView.findViewById(searchImgId);
        v.setImageResource(R.drawable.search_or);

        int searchTextViewId = searchView.getContext().getResources().getIdentifier("Android:id/search_src_text", null, null);
        AutoCompleteTextView searchTextView = (AutoCompleteTextView) searchView.findViewById(searchTextViewId);
        searchTextView.setHintTextColor(getResources().getColor(R.color.hint_color_white));
        searchTextView.setTextColor(getResources().getColor(Android.R.color.white));
        searchTextView.setTextSize(18.0f);


        SpannableStringBuilder ssb = new SpannableStringBuilder("   "); // for the icon
        ssb.append(hintText);
        Drawable searchIcon = getResources().getDrawable(R.drawable.search_or);
        int textSize = (int) (searchTextView.getTextSize() * 1.25);
        searchIcon.setBounds(0, 0, textSize, textSize);
        ssb.setSpan(new ImageSpan(searchIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        searchTextView.setHint(ssb);


        return super.onPrepareOptionsMenu(menu);
    }
2
Pravin Patil

De l'API 21, vous pouvez le changer en XML:

Android:searchIcon="@drawable/loupe"
Android:closeIcon="@drawable/x_white"
2
buxik

Dans le menu xml:

<item
    Android:id="@+id/menu_filter"
    Android:actionLayout="@layout/menu_filter"
    Android:icon="@drawable/ic_menu_filter"
    Android:orderInCategory="10"
    Android:showAsAction="always"
    Android:title="@string/menu_filter"/>

et créez le layout/menu_filter:

<?xml version="1.0" encoding="utf-8"?>
<SearchView
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:searchIcon="@drawable/ic_menu_filter"/>

alors dans l'activité onCreateOptionsMenu ou onPrepareOptionsMenu:

SearchView searchView = (SearchView) menu.findItem(R.id.menu_filter).getActionView();
searchView.setOnQueryTextListener(this);
1
Pnemonic

pour le niveau d'api <21, j'ai fait ceci:

        int searchImgId = getResources().getIdentifier("Android:id/search_mag_icon", null, null);
    ImageView ivIcon = (ImageView) searchView.findViewById(searchImgId);
    if(ivIcon!=null)
        ivIcon.setImageResource(R.drawable.ic_search);

de cette

enter image description here

pour ça

enter image description here

1
Razel Soco

Il y a trois icônes en forme de loupe. deux d'entre eux sont affichés lorsque IconizedByDefault est true (un qui est affiché avant d'appuyer et un est indiqué dans le "conseil") et un est affiché tout le temps quand IconizedByDefault est false. Comme tous les champs sont privés, vous devez les obtenir par leur identifiant XML. (la plupart du code est déjà mentionné séparément dans d'autres réponses de cet article)

lorsque IconizedByDefault est défini sur true, modifiez l'icône dans l'indicateur (visible uniquement après avoir appuyé sur l'icône) en:

mSearchSrcTextView = (SearchAutoComplete)findViewById(R.id.search_src_text);

puis faites la même chose que dans le code source Android:

final int textSize = (int) (mSearchSrcTextView.getTextSize() * 1.25);
    newSearchIconDrawable.setBounds(0, 0, textSize, textSize);

    final SpannableStringBuilder ssb = new SpannableStringBuilder("   ");
    ssb.setSpan(new ImageSpan(newSearchIconDrawable), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    ssb.append(hintText);

mSearchHintIcon a été remplacé par newSearchIconDrawable, qui est votre nouvelle icône de recherche. Ensuite, réglez l'indice avec

mSearchSrcTextView.setHint(ssb); 

Les 2 autres icônes sont dans une ImageView, qui peut être trouvée par leur ID . Pour l'icône lorsque searchview est fermé (lorsque iconizedByDefault est true):

mSearchButton = (ImageView) findViewById(R.id.search_button);

et pour celui qui apparaît toujours (si iconizedByDefault est false)

mCollapsedIcon = (ImageView) findViewById(R.id.search_mag_icon);
1
YehudaW

Une solution désespérée avec Kotlin

    val s = (searchView.getAllChildren().firstOrNull() as? LinearLayout)?.getAllChildren()?.filter { it is AppCompatImageView }?.firstOrNull() as? AppCompatImageView
    s?.setImageResource(R.drawable.search)

getAllChildren:

fun ViewGroup.getAllChildren() : ArrayList<View> {
val views = ArrayList<View>()
for (i in 0..(childCount-1)) {
    views.add(getChildAt(i))
}
return views
}

J'espère que ça aide quelqu'un.

0
Shubham Naik

Nommez simplement votre icône du même nom que l’icône utilisée par la vue de recherche. Lors de la compilation, la ressource du projet est placée sur l'icône de la bibliothèque.

0
SjoerdvGestel

Ma solution: Utiliser deux fichiers XML de menu. Dans l’un des xml, l’élément de menu a une actionView et dans l’autre non. Gonflez d'abord le menu réduit et, lorsque vous cliquez sur l'élément de menu, invalidez le menu et gonflez le menu développé xml et assurez-vous d'appeler setIconified (false);

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{
    if(!mShowSearchView)
    {
        inflater.inflate(R.menu.menu_collapsed, menu);
    }
    else
    {
        inflater.inflate(R.menu.menu_expanded, menu);
        MenuItem searchItem = menu.findItem(R.id.action_search);
        SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
        searchView.setIconified(false);
        searchView.setOnCloseListener(new OnCloseListener()
        {
            @Override
            public boolean onClose()
            {
                mShowSearchView = false;
                ActivityCompat.invalidateOptionsMenu(getActivity());
                return false;
            }
        });
    }
    super.onCreateOptionsMenu(menu, inflater);
}

@Override
public boolean onOptionsItemSelected(MenuItem item)
{
    if (item.getItemId() == R.id.action_filter)
    {
        menu.showMenu();
    }
    else if (item.getItemId() == R.id.action_search)
    {
        mShowSearchView = true;
        ActivityCompat.invalidateOptionsMenu(getActivity());
    }
    return super.onOptionsItemSelected(item);
}
0
Alexandros Ioannou