更改searchview小部件的背景可绘制

我试图改变位于Android actionbar searchview小部件中的drawable。

目前看起来像这样:

但我需要将蓝色背景绘制为红色。

我已经尝试了很多东西来缩小我自己的搜索部件,但似乎没有任何工作。

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


介绍

不幸的是,您无法使用XML中的主题,样式和继承来设置SearchView文本字段样式,就像您可以使用ActionBar下拉列表中的项目背景一样。 这是因为selectableItemBackgroundR.stylable被列为R.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文本字段的背景是通过九个补丁声明的,所以我们将以同样的方式进行。 你可以在Android git仓库的drawable-mdpi目录中找到原始的png图像。 我们对两个图像感兴趣。 一个用于选择文本字段时的状态(名为textfield_search_selected_holo_light.9.png),另一个用于不在其中的位置(名为textfield_search_default_holo_light.9.png)。

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

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

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

我用一个像素的铅笔工具使用GIMP编辑文件(很容易),但你可能会使用你自己的工具。 这是我为定焦状态定制的9个补丁:

注意:为了简单起见,我仅使用mdpi密度的图像。 如果您希望在任何设备上获得最佳效果,则必须为多个屏幕密度创建9个补丁。 Holo SearchView图像可以在mdpi,hdpi和xhdpi 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>

我们将使用上面创建的可绘制设置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构造器中,可以找到一条使布局膨胀的线条:

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.Light值也在该文件中设置。

现在,如果这个属性可以通过R.styleable访问,那很好,但不幸的是它不是。 为了进行比较,请参阅theme.xml和R.attr中的其他主题属性,如textAppearance或selectableItemBackground。 如果searchViewTextField存在于R.attr (和R.stylable )中,那么我们可以简单地使用我们的可绘制选择器来定义XML中整个应用程序的主题。 例如:

<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 。 但是,我们仍然不知道它应该是什么样子。 简而言之,我们搜索用作默认主题值的drawables:textfield_searchview_holo_dark.xml和textfield_searchview_holo_light.xml。 查看内容,我们看到drawable是selector ,它根据视图状态引用另外两个drawable(后面会出现9个补丁)。 你可以在androiddrawables.com上找到(几乎)所有Android版本的聚合9贴片可绘图

定制

我们认识到9个补丁中的一个蓝线,所以我们创建它的本地副本并根据需要更改颜色。


如果您使用的是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);
}

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

链接地址: http://www.djcxy.com/p/92937.html

上一篇: Changing the background drawable of the searchview widget

下一篇: How to validate an email address in PHP