如何更改 Android ActionBar 中 SearchView 默认图标?

59

我在自定义SearchView的搜索图标时遇到了一些麻烦。在我看来,图标可以在Item属性中更改,对吗?请查看下面的代码...

有人能告诉我我做错了什么吗?

这是我使用的菜单,带有我的自定义搜索图标icn_lupa。但是当我运行应用程序时,我总是得到默认的搜索图标...

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

1
我认为@just_user的答案应该被标记为正确。请审核。 :) - Zen
1
最近的支持库android.support.v7.widget.SearchView可以使用app:searchIcon="@drawable/ic_your_custom_icon"进行样式设置。 - Afilu
19个回答

100

我找到了另一种方法来更改搜索图标,与Diego Pino的答案在同一行上,但直接在onPrepareOptionsMenu中进行。

在您的menu.xml文件中(与之前相同)

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

在您的活动中:

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

我按照这个示例更改了EditText的背景。你可以对你的 SearchView 中的所有图标/背景都这样做,要找到正确的ID,您可以在这里查找。

2017年11月更新:

自从此答案发布以来,Android已更新,通过XML可以更改搜索图标。

如果您的目标低于Android v21,则可以使用:

<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" />

或者 v21 及以上版本:

<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" />

还有更多的选项:

closeIcon
commitIcon
goIcon
searchHintIcon
searchIcon
voiceIcon

1
使用标识符“android:id/search_button”是一个很好的想法!我在其他地方都找不到它。非常感谢您的答案!!! - DenisMath
1
太棒了 - 在找到你的解决方案之前,我四处寻找并尝试了许多方法 - 谢谢! - daveywc
1
谢谢,但是当我的搜索视图被展开时仍然使用系统图标。有什么想法吗? - mmlooloo
3
使用SpannableStringBuilder更新提示文本。从安卓源代码中复制以下内容: SpannableStringBuilder ssb = new SpannableStringBuilder(" "); // 用于图标 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); - Pravin Patil
3
我不知道如何使用你的更新版本,你能否也分享一下你的 menu.xml 文件给我们? - azerafati
显示剩余2条评论

37

来自@just_user的不错的答案

对于我的情况,我使用了appcompat v7库来实现SearchView和ActionBar,我稍微修改了他的解决方案以使其与我的项目兼容。只要您在将appcompat v7作为库添加时没有进行任何修改,它应该可以工作。

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>

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

对于这个非常大的图标我很抱歉(我还没有调整它的大小),但它应该可以正常工作。

在此输入图片描述


1
我对Sherlock库做了同样的事情,它起作用了。谢谢。MenuItem searchViewMenuItem = menu.findItem(R.id.search); SearchView mSearchView = (SearchView) searchViewMenuItem.getActionView(); ImageView v = (ImageView) mSearchView.findViewById(com.actionbarsherlock.R.id.abs__search_button); v.setImageResource(R.drawable.ic_action_search); - nmvictor
对于androidx:androidx.appcompat.R.id.search_button。并使用v.setScaleType(ImageView.ScaleType.CENTER_INSIDE);修复ImageView缩放。 - Bad Loser

21

我也曾遇到这个问题,但后来无意中使用了'collapseActionView',结果问题就解决了!现在我的menu.xml看起来是这样的:

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

这样做的缺点是在平板电脑上,搜索视图将出现在操作栏的左侧,而不是搜索图标所在的位置,但我并不介意。


2
我尝试过这个,但实际上它并不起作用。在扩展SearchView之后,按下返回按钮并不能正确地关闭它。相反,在ActionBar的左侧会出现旧图标。需要再次按下返回按钮才能将其正确隐藏。 - Kyle Ivey
它在我的测试设备(SM-G925V)上运行良好,但我不确定有多少其他设备会像Kyle Ivey一样出现奇怪的行为。我确实遇到了Mathieu Post所说的搜索在左侧而不是右侧的相同行为,但这可能是因为我不知道collapseActionView的预期目的。 - Sherlock

15

我定义了一个样式来完成它。

这是我的 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"/>

这是我的风格:

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

就这样了!

完成后,只需查看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>
每个项目都可以通过定义新的样式来覆盖。希望对你有所帮助!

14

有一种方法可以实现这个。诀窍是使用其标识符恢复 ImageView,并使用 setImageResource() 设置新图像。这个解决方案受到了更改搜索视图小部件的背景可绘制对象的启发。

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

1
澄清一下,这是要在搜索视图“展开”时更改默认图标。 - loeschg
谢谢,我可以更改图标。 - Ataru

6

搜索视图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) {
    }

当搜索小部件扩展时,您的解决方案无法正常工作 :( - Bhargav Kumar R

5
在菜单 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"/>

并创建 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"/>

然后在活动的onCreateOptionsMenuonPrepareOptionsMenu中:

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

2
顺便提一下,如果你想调用 getActionView,请使用 app:actionLayout 而不是 android:actionLayout - algrid

5

经过一些研究,我在这里找到了解决方案。诀窍在于图标不是在ImageView中,而是在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);

3
<SearchView
            android:searchIcon="@drawable/ic_action_search"
..../>

使用searchIcon XML标签。

3
看起来actionViewClass覆盖了图标,从该类中似乎无法更改它。
您有两个解决方案:

是的...你说得对...实际上我的搜索图标与默认小部件图标非常相似,但更类似于应用程序中使用的其他图标。 - Valdemar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接