更改searchview小部件的背景drawable

Mar*_*tyn 122 android styles android-actionbar searchview background-drawable

我正在尝试更改位于Android操作栏searchview小部件中的drawable.

目前它看起来像这样: 在此输入图像描述

但我需要将蓝色背景改为红色.

我尝试过很多东西,不用滚动我自己的搜索小部件,但似乎没有任何工作.

有人能指出我改变这个方向的正确方向吗?

vAr*_*rDo 253

介绍

遗憾的是,无法SearchView使用XML中的主题,样式和继承来设置文本字段样式,就像ActionBar下拉列表中的项目背景一样.这是因为selectableItemBackground 被列为设置样式R.stylable,而searchViewTextField(theme属性是我们感兴趣的)不是.因此,我们无法从XML资源中轻松访问它(您将收到No resource found that matches the given name: attr 'android:searchViewTextField'错误).

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

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

注意:下面的解决方案仅取决于其中android:id/search_plate元素的id()SearchView,因此它比儿童遍历更加独立于SDK版本(例如,searchView.getChildAt(0)用于到达正确的视图SearchView),但它不是防弹的.特别是如果某些制造商决定重新实现内部SearchView和上述id的元素不存在 - 代码将不起作用.

在SDK中,文本字段的背景SearchView是通过九个补丁声明的,因此我们将以相同的方式执行.您可以在Android git存储库的drawable-mdpi目录中找到原始png图像.我们对两张图片感兴趣.一个用于选择文本字段时的状态(名为textfield_search_selected_holo_light.9.png),另一个用于不存在的状态(命名为textfield_search_default_holo_light.9.png).

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

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

现在,您需要根据需要编辑下载的九个补丁(即将蓝色更改为红色).您可以使用绘图9补丁工具查看文件,以检查编辑后是否正确定义了文件.

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

在此输入图像描述

注意:为简单起见,我只使用了mdpi密度的图像.如果您希望在任何设备上获得最佳结果,则必须为多个屏幕密度创建9个补丁.Holo的 图像SearchView可以在mdpi,hdpixhdpi drawable中找到.

现在,我们需要创建可绘制选择器,以便根据视图状态显示正确的图像.创建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>
Run Code Online (Sandbox Code Playgroud)

我们将使用上面创建的drawable为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);
    }

}
Run Code Online (Sandbox Code Playgroud)

最终效果

这是最终结果的屏幕截图:

在此输入图像描述

我怎么做到这一点

我认为值得注意的是我如何做到这一点,因此在定制其他视图时可以使用这种方法.

检查视图布局

我已经检查了SearchView布局的样子.在SearchView构造函数中,可以找到一个膨胀布局的行:

inflater.inflate(R.layout.search_view, this, true);
Run Code Online (Sandbox Code Playgroud)

现在我们知道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">
Run Code Online (Sandbox Code Playgroud)

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

调查属性(可以轻松设置吗?)

为了检查searchViewTextField属性的设置方式,我们研究了res/values/themes.xml.SearchView默认情况下有一组属性相关Theme:

<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>
Run Code Online (Sandbox Code Playgroud)

我们看到默认主题的值是@drawable/textfield_searchview_holo_dark.对于Theme.Light,也在该文件中设置.

现在,如果可以通过R.styleable访问此属性会很棒,但不幸的是,它不是.为了进行比较,请参阅themes.xmlR.attr中存在的其他主题属性,如textAppearanceselectableItemBackground.如果存在于(和)中,我们可以在为XML中的整个应用程序定义主题时简单地使用我们的drawable选择器.例如:searchViewTextFieldR.attrR.stylable

<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>
Run Code Online (Sandbox Code Playgroud)

应该修改什么?

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

定制

我们识别9个补丁中的一个中的蓝线,因此我们创建它的本地副本并根据需要更改颜色.


Abd*_*man 31

如果您使用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);
}
Run Code Online (Sandbox Code Playgroud)


Vin*_*eFR 14

你的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);
    }
Run Code Online (Sandbox Code Playgroud)

你的搜索项目menu_search偏离了哪里

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

在此输入图像描述


Dav*_*vra 13

上面的解决方案不适用于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));
}
Run Code Online (Sandbox Code Playgroud)

  • 使用ABS,你将扩展Theme.Sherlock或Theme.Sherlock.Light*而不是*android主题.这意味着您所要做的就是将名为searchViewTextField的项添加到您的应用主题定义中.全部用XML完成,无需代码. (3认同)

Ido*_*Ido 5

我也厌倦了这样做,我正在使用v7.当我试图抓住searchPlate通道时,应用程序崩溃了getIdentifier()所以我这样做了:

View searchPlate = searchView.findViewById(android.support.v7.appcompat.R.id.search_plate);
Run Code Online (Sandbox Code Playgroud)