如何更改 SearchView 上的默认图标,以便在 Android 的操作栏中使用?

Posted

技术标签:

【中文标题】如何更改 SearchView 上的默认图标,以便在 Android 的操作栏中使用?【英文标题】:How to change the default icon on the SearchView, to be use in the action bar on Android? 【发布时间】:2012-05-13 19:36:24 【问题描述】:

我在自定义 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>

提前致谢。

【问题讨论】:

我认为@just_user 的答案应该被标记为正确。请查阅。 :) 最近支持库android.support.v7.widget.SearchView可以用app:searchIcon="@drawable/ic_your_custom_icon"设置样式 【参考方案1】:

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

我按照这个example中更改编辑文本的示例。

您应该能够对SearchView 中的所有图标/背景执行此操作,要找到正确的 ID,您可以检查 here。

希望这对其他人也有帮助!

2017 年 11 月更新:

自从这个答案以来,android 已经更新,可以通过 XML 更改搜索图标。

如果你定位低于 android v21 的任何东西,你可以使用:

<android.support.v7.widget.SearchView
    android:layout_
    android:layout_
    app:searchIcon="@drawable/ic_search_white_24dp"
    app:closeIcon="@drawable/ic_clear_white_24dp" />

或 v21 及更高版本:

<SearchView
    android:layout_
    android:layout_
    android:searchIcon="@drawable/ic_search_white_24dp"
    android:closeIcon="@drawable/ic_clear_white_24dp" />

还有更多选择:

closeIcon
commitIcon
goIcon
searchHintIcon
searchIcon
voiceIcon

【讨论】:

使用标识符“android:id/search_button”是个好主意!我在其他任何地方都找不到。非常感谢您的回答!!! 精彩 - 在找到解决方案之前搜索了高低并尝试了很多东西 - 谢谢! 谢谢,但是当我的搜索视图展开时,仍然使用系统图标。有什么想法吗? 使用 SpannableStringBuilder 更新提示。从android源复制以下, SpannableStringBuilder ssb = new SpannableStringBuilder(" "); // 对于图标 ssb.append(hintText);可绘制的 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); 我不知道如何使用您的更新版本,您也可以与我们分享您的menu.xml 吗?【参考方案2】:

@just_user 的好回答

就我而言,由于我使用的是 SearchView + ActionBar 的 appcompat v7 库,因此我稍微修改了他的解决方案以使其与我的项目兼容,只要您在添加时没有修改任何内容,它就应该可以工作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);

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

【讨论】:

我对 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); 对于 androidx:androidx.appcompat.R.id.search_button。并使用 v.setScaleType(ImageView.ScaleType.CENTER_INSIDE); 修复 ImageView 缩放【参考方案3】:

我也在为此苦苦挣扎,但后来我不小心使用了“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 所在的位置,但我不介意。

【讨论】:

我试过了,真的不行。展开搜索视图后,按下后​​退按钮不会正确关闭它。相反,旧图标出现在操作栏的左侧。需要再次按下后退按钮才能正确隐藏它。 它适用于我的测试设备 (SM-G925V),但我不确定有多少其他设备会像 Kyle Ivey 那样出现奇怪的行为。我确实有与 Mathieu Post 所说的相同的行为,即搜索在左侧而不是右侧,但这可能是因为我不知道 collapseActionView 的预期目的。【参考方案4】:

我定义了一种风格来做到这一点。

这是我的 xml:

  <android.support.v7.widget.SearchView
        android:id="@+id/sv_search"
        android:icon="@android:drawable/ic_menu_search"
        android:layout_
        **style="@style/CitySearchView"**
        android:layout_/>

这是我的风格:

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

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

希望对你有帮助!

【讨论】:

【参考方案5】:

有办法做到这一点。诀窍是使用它的标识符恢复 ImageView 并使用setImageResource() 设置一个新图像。此解决方案的灵感来自 Changing the background drawable of the searchview widget。

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

【讨论】:

澄清一下,这是在搜索视图“展开”时更改默认图标。 谢谢你,我可以改变图标。【参考方案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) 
    

【讨论】:

搜索小部件展开时您的解决方案不起作用:(【参考方案7】:

经过一番研究,我找到了解决方案here。诀窍是图标不在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);

【讨论】:

【参考方案8】:

在菜单 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_
    android:layout_
    android:searchIcon="@drawable/ic_menu_filter"/>

然后在活动的onCreateOptionsMenuonPrepareOptionsMenu

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

【讨论】:

顺便说一句,如果你想打电话给getActionView,请使用app:actionLayout 而不是android:actionLayout【参考方案9】:

看起来 actionViewClass 覆盖了图标,而且您似乎无法从 this class 更改它。

你有两个解决方案:

接受它,我认为它是用户体验和平台一致性方面的最佳选择。 Define your own actionViewClass

【讨论】:

是的...你是对的...实际上我的搜索图标与默认的小部件图标非常相似,但与应用程序中使用的其余图标更相似。【参考方案10】:
<SearchView
            android:searchIcon="@drawable/ic_action_search"
..../>

使用 searchIcon xml 标签

【讨论】:

【参考方案11】:

这适用于 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);
    

【讨论】:

【参考方案12】:

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

【讨论】:

关于如何更改关闭图标的任何想法?【参考方案13】:

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

android:searchIcon="@drawable/loupe"
android:closeIcon="@drawable/x_white"

【讨论】:

这也适用于低于 api 级别 21 的当前兼容库(刚刚测试了 searchIcon)。工具栏和 AppCompat 库 v7:23 中的 SearchView【参考方案14】:

对于 api 级别

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

从这里

到这里

【讨论】:

【参考方案15】:

共有三个放大镜图标。其中两个在 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 为 false)

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

【讨论】:

【参考方案16】:

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

希望它对某人有所帮助。

【讨论】:

【参考方案17】:

我的解决方案: 使用两个菜单 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);

【讨论】:

【参考方案18】:

只需将您的图标命名为与搜索视图使用的图标相同的名称。编译时,它会将项目中的资源置于库中的图标之上。

【讨论】:

【参考方案19】:

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

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

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

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

【讨论】:

以上是关于如何更改 SearchView 上的默认图标,以便在 Android 的操作栏中使用?的主要内容,如果未能解决你的问题,请参考以下文章

如何更改 SearchView 默认图标?

更改 SearchView 上的工具栏颜色/样式单击

为 Android TV 应用程序更改 BrowseFragment 的 SearchView 默认图标?

是否可以更改 Android SearchView 上的文本颜色?

Primefaces:如何更改日历字段按钮上的默认图标?

Flutter Maps:如何更改标记点击上的标记图标