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

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

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

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

我已经尝试了很多东西,滚动我自己的search部件,但似乎没有任何工作。

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

介绍

不幸的是,没有办法像使用ActionBar下拉菜单中的项目背景一样,使用XML中的主题,样式和inheritance来设置SearchView文本字段样式。 这是因为selectableItemBackgroundR.stylable 作为样式列出 ,而searchViewTextField (我们感兴趣的主题属性)不是。 因此,我们无法从XML资源中轻松访问它(您将得到一个No resource found that matches the given name: attr 'android:searchViewTextField' )。

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

所以,正确replaceSearchView文本字段的背景的唯一方法是进入它的内部,获取基于searchViewTextField具有背景设置的视图并设置我们自己的。

注意:下面的解决scheme仅依赖于SearchView中元素的id( android:id/search_plate ),所以它比儿童遍历更独立于SDK版本(例如,使用searchView.getChildAt(0)SearchView获得正确的视图)这不是防弹的。 特别是如果一些制造商决定重新实现SearchView内部和上面提到的ID元素不存在的代码将无法正常工作。

在SDK中, SearchView文本字段的背景是通过九个补丁声明的,所以我们将以同样的方式进行。 你可以在Android git仓库的 drawable-mdpi目录中find原始的png图像。 我们对两个图像感兴趣。 一个用于select文本字段的状态(名为textfield_search_selected_holo_light.9.png ),另一个用于不在的位置(名为textfield_search_default_holo_light.9.png )。

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

注意:我使用的是Holo Light主题作为基础,但是您也可以使用Holo Dark做同样的事情。 看起来光和 黑暗主题之间的select状态 9补丁没有真正的区别。 然而, 默认状态下的 9个补丁有所不同(见Light vs Dark )。 所以,可能不需要为选定的状态制作9个补丁的本地副本,无论是黑暗主题还是灯光主题(假设你想要处理两者,并使它们看起来与Holo主题相同)。 只需制作一个本地副本,并将其用于两个主题的select器drawable

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

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

在这里输入图像描述

注意:为了简单起见,我只使用了mdpi密度的图像。 如果需要在任何设备上获得最佳结果,则必须为多个屏幕密度创build9个补丁Holo SearchView图像可以在mdpi , hdpi和xhdpi中find。

现在,我们需要创build可绘制的select器,以便根据视图状态显示正确的图像。 使用以下内容创build文件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> 

我们将使用上面创build的drawable来为在SearchView中保存文本字段的LinearLayout视图设置背景 – 它的id是android:id/search_plate 。 因此,在创build选项菜单时,如何在代码中快速执行此操作:

 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构造函数中,可以find一条膨胀布局的行:

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

现在我们知道SearchView布局的文件名为res/layout/search_view.xml 。 看着search_view.xml,我们可以find一个内部的LinearLayout元素(ID为search_plate ),里面有android.widget.SearchView$SearchAutoComplete (看起来像我们的search视图文本字段):

  <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 )中,我们可以简单地使用我们的可绘制select器来定义我们整个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 。 但是,我们仍然不知道应该如何。 简而言之,我们search用作默认主题值的drawables: textfield_searchview_holo_dark.xml和textfield_searchview_holo_light.xml 。 查看内容,我们看到drawable是基于视图状态引用另外两个drawable(后面会出现9个补丁)的selector 。 你可以在androiddrawables.com上find(几乎)所有版本的Android的9-patch drawable

定制

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

如果您正在使用appcompat库,上述解决scheme可能无法正常工作。 您可能需要修改代码才能使其适用于appcompat库。

这是appcompat库的工作解决scheme。

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

在那里你的search项目是menu_search off课程

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

在这里输入图像描述

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

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

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

首先,我们创build一个名为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将被用作我们search小部件的背景。 我将颜色设置为红色,因为这是您要求的,但是您可以将其设置为由@color标记定义的任何颜色。 你甚至可以使用为形状标签定义的属性(使圆angular,做一个椭圆形的背景等)进一步修改它。

下一步是将我们的search小部件的背景设置为这个。 这可以通过以下来完成:

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

我也面临同样的问题。我使用了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, ie 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/

 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>