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>

提前致谢。

4

19 回答 19

98

我找到了另一种更改搜索图标的方法,该图标与 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);
}

我按照示例更改了此示例中的编辑文本。

您应该能够为您的所有图标/背景执行此操作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
于 2013-08-21T14:43:20.670 回答
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);
}

请原谅这个非常大的图标(我还没有调整图标的大小),但它应该可以正常工作。

在此处输入图像描述

于 2014-08-02T06:17:53.813 回答
20

我也在为此苦苦挣扎,但后来我不小心使用了“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>

这样做的缺点是,在平板电脑上,SearchView 将出现在 ActionBar 的左侧,而不是 searchicon 所在的位置,但我不介意。

于 2013-07-20T13:53:18.370 回答
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>

就是它!</p>

完成之后,看看 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>

每个项目都可以通过定义新样式来覆盖。

希望能帮助到你!

于 2015-04-17T07:40:22.023 回答
14

有办法做到这一点。诀窍是使用它的标识符恢复 ImageView 并使用setImageResource(). 此解决方案的灵感来自于更改 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));        
}
于 2013-06-07T16:19:43.160 回答
6

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) {
    }
于 2014-08-26T12:47:39.243 回答
5

After some research I found the solution here. The trick is that the icon is not in an ImageView but in the Spannable object.

// 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);
于 2014-05-13T20:27:45.770 回答
4

在菜单 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);
于 2018-02-28T09:29:50.247 回答
3

看起来 actionViewClass 覆盖了图标,并且看起来您无法从此类更改它。

你有两个解决方案:

于 2012-05-04T09:11:12.733 回答
3

这适用于 Material Design(MaterialComponents 主题)和 BottomAppBar。

如果您使用的是 androidx 库,例如:

 <item
    android:id="@+id/sv"
    android:title="@string/search"
    app:actionViewClass="androidx.appcompat.widget.SearchView"
    app:showAsAction="always" />

您可以创建一个方法并从任何您想要的地方调用它:

  /**
 * Set SearchView Icon
 * @param i Drawable icon
 */
private void setSVIcon(int i) {
    ImageView iv = searchView.findViewById(androidx.appcompat.R.id.search_button);
    iv.setImageDrawable(ResourcesCompat.getDrawable(getResources(), i, null));
}

使用示例:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(m, menu);
    MenuItem mn = menu.findItem(R.id.sv);
    if (mn != null) {
        searchview = (SearchView) mn.getActionView();
        setSVIcon(R.drawable.ic_sr);
    }
}
于 2019-06-28T23:40:24.923 回答
3
<SearchView
            android:searchIcon="@drawable/ic_action_search"
..../>

使用 searchIcon xml 标签

于 2016-04-04T19:15:27.803 回答
2

更新 AutocompleteTextView 的提示,用于在扩展模式下更新搜索图标,从 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);
    }
于 2014-11-03T19:05:03.843 回答
1

从 API 21,您可以在 xml 中更改它:

android:searchIcon="@drawable/loupe"
android:closeIcon="@drawable/x_white"
于 2015-01-26T09:21:04.883 回答
1

使用 Kotlin 的绝望解决方案

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

获取所有儿童:

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

希望它可以帮助某人。

于 2017-12-07T11:57:55.453 回答
1

对于 api 级别 < 21,我这样做了:

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

由此

在此处输入图像描述

对此

在此处输入图像描述

于 2015-07-09T04:48:08.883 回答
1

有三个放大镜图标。其中两个在 IconizedByDefault 为真时显示(一个在按下之前显示,一个在“提示”中显示),一个在 IconizedByDefault 为假时始终显示。所有字段都是私有的,因此获取它们的方法是通过它们的 xml id。(大部分代码已经在这篇文章的其他答案中单独提及)

当 IconizedByDefault 为 true 时,将提示中的图标(仅在按下图标后可见)更改为:

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

然后执行与 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 已替换为 newSearchIconDrawable,这是您的新搜索图标。然后设置提示

mSearchSrcTextView.setHint(ssb); 

其他 2 个图标位于 中ImageView,可通过其 ID 找到。对于搜索视图关闭时的图标(当 iconizedByDefault 为 true 时),请执行以下操作:

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

对于总是出现的那个(如果 iconizedByDefault 为假)

mCollapsedIcon = (ImageView) findViewById(R.id.search_mag_icon);
于 2016-11-21T11:26:47.617 回答
0

Just name your icon the same name as the icon that is used by the search view. When it compiles it takes the resource in the project over the icon in the library.

于 2014-07-16T14:06:08.767 回答
0

我的解决方案:使用两个菜单 xml 文件。在其中一个 xml 中,菜单项有一个 actionView,而在另一个没有。最初膨胀折叠的菜单,当单击菜单项时,使菜单无效并膨胀展开的菜单 xml 并确保调用 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);
}
于 2013-08-27T17:07:27.940 回答
-1

我使用 AppCompat 库。是的,指定android:icon="@drawable/search_icon_png"不起作用。所以我查看了@style/Theme.AppCompat 的源代码,找到了android 使用的图标。

<item name="searchViewSearchIcon">@drawable/abc_ic_search</item>

因此,如果您将 drawables 中的搜索图标重命名为abc_ic_search.png,则此图标将首先在您的应用程序可绘制对象中找到,而不是在 appcompat 可绘制文件夹中找到。为我工作:)

使用这种方法,您也可以自定义搜索小部件的关闭和清除图标。

于 2014-04-03T22:36:53.517 回答