首页 文章

更改searchview小部件的背景drawable

提问于
浏览
119

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

目前它看起来像这样:
enter image description here

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

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

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

9 回答

  • 249

    简介

    遗憾的是,无法使用XML中的主题,样式和继承来设置 SearchView 文本字段样式can do with background of items in ActionBar dropdown . 这是因为 selectableItemBackground is listed as styleableR.stylable 中,而 searchViewTextField (主题属性我们're interested in) is not. Thus, we cannot access it easily from within XML resources (you' ll得到 No resource found that matches the given name: attr 'android:searchViewTextField' 错误) .

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

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

    NOTE: 下面的解决方案仅取决于 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) .

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

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

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

    我使用GIMP使用一个像素的铅笔工具编辑文件(非常简单),但是'll probably use the tool of your own. Here'是我的自定义9补丁,用于聚焦状态:

    enter image description here

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

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

    最终效果

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

    enter image description here

    我是怎么做到这一点的

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

    检出视图布局

    我已经检查了 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 . 默认情况下 SearchView 有一组与 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>
    

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

    现在,如果通过R.styleable可以访问此属性会很棒,但不幸的是,它不是 . 为了进行比较,请参阅themes.xmlR.attr中存在的其他主题属性,如textAppearanceselectableItemBackground . 如果在 R.attr (和 R.stylable )中存在 searchViewTextField ,我们可以在为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 . 但是,我们仍然不知道它应该是什么样子 . 简而言之,我们搜索在默认主题中用作值的drawable:textfield_searchview_holo_dark.xmltextfield_searchview_holo_light.xml . 看一下内容,我们看到drawable是 selector ,它基于视图状态引用了另外两个drawable(后来发生了9个补丁) . 您可以在androiddrawables.com上找到来自(几乎)所有Android版本的聚合9-patch drawables

    自定义

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

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

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

    enter image description here

  • 3

    上面的解决方案不适用于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));
    }
    
  • 0

    我've tired to do this as well and I'm使用v7 . 当我试图通过 getIdentifier() 抓取 searchPlate 时,应用程序崩溃了,所以我这样做了:

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

    我也遇到了同样的问题 . 我使用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>
    

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

  • 1

    首先,让我们创建一个名为search_widget_background.xml的XML文件,用作drawable,即在drawable目录下 .

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

    此drawable将用作我们的搜索小部件的背景 . 我将颜色设置为红色,因为这是您要求的,但您可以将其设置为@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);
    ...
        }
    
  • 13
    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 );
    ........
        }
    

    and this is the searchablecolor.xml file

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

    我在这篇文章的最后用图像解释这适用于xamarin表格 . 但我认为你可以理解它,因为它是基于android的searchview的源代码

    How to change searchbar cancel button image in xamarin forms

相关问题