【问题标题】:Changing the background drawable of the searchview widget更改 searchview 小部件的背景可绘制对象
【发布时间】:2012-06-20 13:37:59
【问题描述】:

我正在尝试更改位于 Android 操作栏搜索视图小部件中的可绘制对象。

目前它看起来像这样:

但我需要将可绘制的蓝色背景更改为红色。

除了滚动自己的搜索小部件外,我尝试了很多方法,但似乎没有任何效果。

有人可以指出我改变这一点的正确方向吗?

【问题讨论】:

  • 我相信this SO post 可以帮助你完成你想要完成的事情,如果你还没有检查过的话。
  • @Angelo 不幸的是,这在SearchView 背景下是不可能的,因为它不能通过R.styleable 获得。我在下面的回答描述了如何在代码中做到这一点。
  • 你是如何得到“输入电影名称”的文字的?
  • 您可以像这样在搜索视图中设置提示文本: SearchView.SearchAutoComplete searchAutoComplete = (SearchView.SearchAutoComplete) searchView.findViewById(android.support.v7.appcompat.R.id.search_src_text); searchAutoComplete.setHint("提示文本");

标签: android styles android-actionbar searchview background-drawable


【解决方案1】:

首先,让我们创建一个名为 search_widget_background.xml 的 XML 文件,用作可绘制对象,即在可绘制目录下。

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

这个可绘制对象将用作我们的搜索小部件的背景。我将颜色设置为红色,因为这是您要求的,但您可以将其设置为 @color 标签定义的任何颜色。您甚至可以使用为shape tag 定义的属性进一步修改它(制作圆角、制作椭圆背景等)。

下一步是将我们的搜索小部件的背景设置为此。这可以通过以下方式完成:

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

【讨论】:

  • @shkschneider 恕我直言,这是行不通的,因为必须在SearchView(命名为search_plate)内的元素上设置背景,而不是SearchView本身。有关更多详细信息,请参阅我的答案。但是,我不得不承认,我没有尝试使用@(baba tenor) 的答案。
  • 没有注意到 SearchView 在 ActionBar 中。现在它应该可以工作了。
  • @babatenor 这不起作用,因为SearchView 本身的背景将始终低于SearchView 内部元素的背景。在SearchView 内有一个LinearLayout 视图,其ID 为search_plate,它设置了这个蓝色下划线元素作为背景。有关详细信息,请参阅我的答案。因此,使用您的解决方案,结果是整个小部件的蓝色背景,蓝色下划线仍然可见。我在 Jelly Bean 上进行了测试,但我认为 SDK 目标版本在这里并不重要。
  • 谢谢 vArDo。我知道 SearchView 的分层结构,但我只是假设这会起作用(至少在我看来它是合乎逻辑的)。
  • @babatenor 如果它有效,那就太好了,所以所有这些黑客都是不必要的:)
【解决方案2】:

简介

不幸的是,您无法像can do with background of items in ActionBar dropdown 那样使用 XML 中的主题、样式和继承来设置 SearchView 文本字段样式。这是因为selectableItemBackground is listed as styleableR.stylable 中,而searchViewTextField(我们感兴趣的主题属性)不是。因此,我们无法从 XML 资源中轻松访问它(您将收到 No resource found that matches the given name: attr 'android:searchViewTextField' 错误)。

从代码中设置 SearchView 文本字段背景

因此,正确替换 SearchView 文本字段背景的唯一方法是进入其内部,获取对基于 searchViewTextField 设置背景的视图的访问权限并设置我们自己的。

注意: 下面的解决方案仅取决于 SearchView 中元素的 id (android:id/search_plate),因此它比子遍历更独立于 SDK 版本(例如,使用 searchView.getChildAt(0) 到达SearchView) 中的正确视图,但它不是防弹的。尤其是如果某些制造商决定重新实现 SearchView 的内部结构并且具有上述 id 的元素不存在 - 代码将无法正常工作。

在 SDK 中,SearchView 中的文本字段的背景是通过nine-patches 声明的,所以我们会这样做。您可以在Android git repositorydrawable-mdpi 目录中找到原始png 图像。我们对两个图像感兴趣。一种用于选择文本字段时的状态(命名为textfield_search_selected_holo_light.9.png),另一种用于未选择文本字段的状态(命名为textfield_search_default_holo_light.9.png)。

不幸的是,即使您只想自定义 focused 状态,您也必须为这两个图像创建本地副本。这是因为textfield_search_default_holo_light 不存在于R.drawable 中。因此,它不容易通过@android:drawable/textfield_search_default_holo_light 访问,可以在下面显示的选择器中使用,而不是引用本地drawable。

注意:我使用的是 Holo Light 主题作为基础,但您可以使用 Holo Dark 做同样的事情。 LightDark 主题之间的 选定状态 9 补丁似乎没有真正的区别。但是,默认状态的 9 个补丁存在差异(请参阅 LightDark)。因此,对于 DarkLight 主题,可能不需要为 selected state 制作 9 补丁的本地副本(假设您想要处理两者,并使它们看起来与 Holo 主题 中的相同)。只需制作一个本地副本并在 selector drawable 中为两个主题使用它。

现在,您需要根据需要编辑下载的九个补丁(即将蓝色更改为红色)。您可以使用draw 9-patch tool 查看文件,以检查在您编辑后它是否正确定义。

我使用GIMP 和单像素铅笔工具(非常简单)编辑了文件,但您可能会使用自己的工具。这是我为 focused state 定制的 9 补丁:

注意:为简单起见,我仅使用图像来表示 mdpi 密度。如果您想在任何设备上获得最佳效果,则必须为多种屏幕密度创建 9-patchesHolo SearchView 的图像可以在 mdpihdpixhdpidrawable 中找到。

现在,我们需要创建可绘制选择器,以便根据视图状态显示正确的图像。创建文件res/drawable/texfield_searchview_holo_light.xml,内容如下:

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

我们将使用上面创建的可绘制对象为 LinearLayout 视图设置背景,该视图在 SearchView 中保存文本字段 - 它的 id 是 android:id/search_plate。因此,在创建选项菜单时,以下是如何在代码中快速执行此操作:

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

}

最终效果

这是最终结果的截图:

我是怎么做到的

我认为值得一提的是我是如何做到这一点的,以便在自定义其他视图时可以使用这种方法。

查看视图布局

我检查了SearchView 布局的样子。在SearchView contructor 中可以找到一条使布局膨胀的行:

inflater.inflate(R.layout.search_view, this, true);

现在我们知道SearchView 布局在名为res/layout/search_view.xml 的文件中。查看search_view.xml,我们可以找到一个内部LinearLayout 元素(id 为search_plate),其中包含android.widget.SearchView$SearchAutoComplete(看起来像我们的搜索视图文本字段):

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

现在,我们现在根据当前主题的searchViewTextField 属性设置背景。

调查属性(是否容易设置?)

为了检查searchViewTextField 属性是如何设置的,我们调查res/values/themes.xml。默认Theme中有一组与SearchView相关的属性:

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

我们看到默认主题的值为@drawable/textfield_searchview_holo_dark。对于Theme.Lightis also set in that file

现在,如果可以通过R.styleable 访问此属性,那就太好了,但不幸的是,事实并非如此。为了比较,请参阅themes.xmlR.attr 中都存在的其他主题 属性,例如textAppearanceselectableItemBackground。如果searchViewTextField 出现在R.attr(和R.stylable)中,我们可以在为整个XML 应用程序定义主题时简单地使用我们的drawable 选择器。例如:

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

应该修改什么?

现在我们知道,我们必须通过代码访问search_plate。但是,我们仍然不知道它应该是什么样子。简而言之,我们搜索在默认主题中用作值的可绘制对象:textfield_searchview_holo_dark.xmltextfield_searchview_holo_light.xml。查看内容,我们看到可绘制对象是 selector,它基于视图状态引用了另外两个可绘制对象(稍后会出现 9 个补丁)。您可以在androiddrawables.com上找到来自(几乎)所有 Android 版本的聚合 9-patch drawables

定制

我们识别出one of the 9-patches 中的蓝线,因此我们创建它的本地副本并根据需要更改颜色。

【讨论】:

  • 你的java代码不行,他的SearchView在ActionBar中,用findViewById方法找不到。但其余的都是正确的!
  • @VinceFR 感谢您指出这一点。没有注意到它(我专注于SearchView 本身)。如果我将您的答案(覆盖 onCreateOptionsMenu)合并到我的答案中可以吗?
  • @VinceFR 按照您的建议,我已将代码从 onCreate() 方法移至 onCreateOptionsMenu() 方法。投票赞成你的答案。
  • 非常感谢:D 有什么方法可以以类似的方式更改 Mag 图标和 Close 图标吗?
  • 我们如何更改放大镜图标?我尝试了一切,但我无法更改它...谢谢...以及如何在 sherlock 操作栏中执行此操作?
【解决方案3】:

您的onCreateOptionsMenu 方法必须是:

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

您的搜索项目在哪里是menu_search 偏离路线

这里是searchviewredversion(这个是xhdpi版本):http://img836.imageshack.us/img836/5964/searchviewredversion.png

【讨论】:

  • 有没有办法以类似的方式更改搜索图标和关闭按钮?
  • 我不知道 SherlockActionBar 4.2 但是你可以用同样的方式更改搜索图标和关闭按钮!
  • ActionbarSherlock 有自己的主题并定义了自己的 SearchView。这意味着您只需将一个名为 searchViewTextField 的项目添加到您的主题中,并使用上面的可绘制定义和 9 个补丁。
  • 不要忘记将文件重命名为 searchviewredversion.9.png 以指示将资产导出为 9-patch
【解决方案4】:

上述解决方案不适用于 ActionBarSherlock 4.2,因此它不能向后兼容 Android 2.x。这是在 ActionBarSherlock 4.2 上设置 SearchView 背景和提示文本的工作代码:

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

【讨论】:

  • 我应该把这段代码放在哪里?我正在尝试在 4.2 版本的操作栏中执行此操作。我的问题stackoverflow.com/questions/13992424/…
  • 嗨,从 onCreateOptionsMenu 方法调用它。找到 searchView 并将其传递给此方法。
  • 谢谢。知道如何删除该内联 Mag 符号,如此处所示i.imgur.com/YvBz2.png
  • 使用 ABS,您将扩展 Theme.Sherlock 或 Theme.Sherlock.Light not android 主题。这意味着您所要做的就是将名为 searchViewTextField 的项目添加到您的应用程序主题定义中。全部在 XML 中完成,无需代码。
【解决方案5】:

如果您使用的是 appcompat 库,上述解决方案可能不起作用。您可能需要修改代码以使其适用于 appcompat 库。

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

【讨论】:

  • 这不适用于 search_mag_icon。它给出“样式包含输入错误的键:0x01010479”
  • 搜索板对我不起作用(它有作用,但我看不到底线有任何变化),但 AppCompat 的总体思路非常有帮助
【解决方案6】:

我也遇到了同样的问题。我使用了 appcompat v7 库并为其定义了自定义样式。 在drawable文件夹中放置bottom_border.xml文件,如下所示:

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

在值文件夹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>

我定义了用于显示菜单的 custommenu.xml 文件:

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

您的活动应该扩展 ActionBarActivity 而不是 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);
}

在清单文件中:

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppnewTheme" >

有关更多信息,请参见此处:
这里http://www.jayway.com/2014/06/02/android-theming-the-actionbar/

【讨论】:

【解决方案7】:
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 );
........
    }

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

【讨论】:

    【解决方案8】:

    我也厌倦了这样做,我正在使用 v7。 当我尝试通过getIdentifier() 获取searchPlate 时,应用程序崩溃了,所以我这样做了:

    View searchPlate = searchView.findViewById(android.support.v7.appcompat.R.id.search_plate);
    

    【讨论】:

      【解决方案9】:

      我在这篇文章的最后用图片解释了 这适用于 xamarin 表格。不过我想你可以理解,因为它是基于android的searchview的源码

      How to change searchbar cancel button image in xamarin forms

      【讨论】:

        【解决方案10】:

        更新

        如果您使用的是 AndroidX,那么您可以这样做

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

        【讨论】:

          【解决方案11】:

          如果您像这样“getMenuInflater().inflate(R.menu.search_menu, menu);”来膨胀 Searchview。然后您可以通过 style.xml 自定义此搜索视图,如下所示。

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

          【讨论】:

            【解决方案12】:

            我研究了很多,最后我找到了这个解决方案,它对我有用!
            你可以用这个

            如果你使用 appcompat 试试这个:

            ImageView searchIconView = (ImageView) searchView.findViewById(android.support.v7.appcompat.R.id.search_button);
            searchIconView.setImageResource(R.drawable.yourIcon);
            

            如果你使用 androidx 试试这个:

            ImageView searchIconView = (ImageView) searchView.findViewById(androidx.appcompat.R.id.search_button);
                searchIconView.setImageResource(R.drawable.yourIcon);
            

            它将更改默认的 serchview 图标。

            希望对你有帮助!

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-04-24
              • 1970-01-01
              • 2013-03-25
              • 1970-01-01
              • 2013-08-28
              • 2013-11-18
              • 1970-01-01
              • 2023-03-19
              相关资源
              最近更新 更多