Android 更改 searchview 小部件的背景可绘制
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11085308/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Changing the background drawable of the searchview widget
提问by Martyn
I'm trying to change the drawable that sits in the Android actionbar searchview widget.
我正在尝试更改位于 Android 操作栏搜索视图小部件中的可绘制对象。
Currently it looks like this:
目前它看起来像这样:
but I need to change the blue background drawable to a red colour.
但我需要将可绘制的蓝色背景更改为红色。
I've tried many things short of rolling my own search widget, but nothing seems to work.
除了滚动我自己的搜索小部件之外,我已经尝试了很多东西,但似乎没有任何效果。
Can somebody point me in the right direction to changing this?
有人可以指出我改变这一点的正确方向吗?
回答by vArDo
Intro
介绍
Unfortunately there's no way to set SearchView
text field style using themes, styles and inheritance in XML as you can do with background of items in ActionBar dropdown. This is because selectableItemBackground
is listed as styleablein R.stylable
, whereas searchViewTextField
(theme attribute that we're interested in) is not. Thus, we cannot access it easily from within XML resources (you'll get a No resource found that matches the given name: attr 'android:searchViewTextField'
error).
不幸的是,没有办法SearchView
使用 XML 中的主题、样式和继承来设置文本字段样式,就像您可以在 ActionBar 下拉菜单中设置项目背景一样。这是因为selectableItemBackground
被列为设置样式的R.stylable
,而searchViewTextField
(theme属性是我们感兴趣的)没有。因此,我们无法从 XML 资源中轻松访问它(您将收到No resource found that matches the given name: attr 'android:searchViewTextField'
错误消息)。
Setting SearchView text field background from code
从代码设置 SearchView 文本字段背景
So, the only way to properly substitute background of SearchView
text field is to get into it's internals, acquire access to view that has background set based on searchViewTextField
and set our own.
因此,正确替换SearchView
文本字段背景的唯一方法是进入它的内部结构,获取对基于searchViewTextField
并设置我们自己的背景设置的视图的访问权限。
NOTE:Solution below depends only on id (android:id/search_plate
) of element within SearchView
, so it's more SDK-version independent than children traversal (e.g. using searchView.getChildAt(0)
to get to the right view within SearchView
), but it's not bullet-proof. Especially if some manufacturer decides to reimplement internals of SearchView
and element with above-mentioned id is not present - the code won't work.
注意:下面的解决方案仅取决于android:id/search_plate
中元素的id ( ) SearchView
,因此它比子遍历更独立于 SDK 版本(例如,searchView.getChildAt(0)
用于获得 中的正确视图SearchView
),但它不是防弹的。特别是如果某些制造商决定重新实现SearchView
具有上述 id 的元素的内部结构不存在 - 代码将无法工作。
In SDK, the background for text field in SearchView
is declared through nine-patches, so we'll do it the same way. You can find original pngimages in drawable-mdpidirectory of Android git repository. We're interested in two image. One for state when text field is selected (named textfield_search_selected_holo_light.9.png) and one for where it's not (named textfield_search_default_holo_light.9.png).
在 SDK 中,文本字段 in 的背景SearchView
是通过9 个补丁声明的,因此我们将按照相同的方式进行声明。您可以在Android git 存储库的drawable-mdpi目录中找到原始png图片。我们对两张图片感兴趣。一种用于选择文本字段时的状态(名为textfield_search_selected_holo_light.9.png),另一种用于未选择的状态(名为textfield_search_default_holo_light.9.png)。
Unfortunately, you'll have to create local copies of both images, even if you want to customize only focusedstate. This is because textfield_search_default_holo_light
is not present in R.drawable. Thus it's not easily accessible through @android:drawable/textfield_search_default_holo_light
, which could be used in selector shown below, instead of referencing local drawable.
不幸的是,即使您只想自定义聚焦状态,您也必须创建两个图像的本地副本。这是因为R.drawable 中textfield_search_default_holo_light
不存在。因此它不容易通过 访问,可以在下面显示的选择器中使用,而不是引用本地可绘制对象。@android:drawable/textfield_search_default_holo_light
NOTE:I was using Holo Lighttheme as base, but you can do the same with Holo Dark. It seems that there's no real difference in selected state9-patches between Lightand Darkthemes. However, there's a difference in 9-patches for default state(see Lightvs Dark). So, probably there's no need to make local copies of 9-patches for selected state, for both Darkand Lightthemes (assuming that you want to handle both, and make them both look the same as in Holo Theme). Simply make one local copy and use it in selector drawablefor both themes.
注意:我使用Holo Light主题作为基础,但您可以使用Holo Dark做同样的事情。似乎在Light和Dark主题之间的选定状态9 补丁中没有真正的区别。但是,默认状态的9 个补丁存在差异(请参阅Lightvs Dark)。因此,对于Dark和Light主题,可能没有必要为selected state制作 9-patches 的本地副本(假设您想要处理两者,并使它们看起来与Holo Theme 中的相同)。只需制作一份本地副本并将其用于两个主题均可绘制的选择器。
Now, you'll need to edit downloaded nine-patches to your need (i.e. changing blue color to red one). You can take a look at file using draw 9-patch toolto check if it is correctly defined after your edit.
现在,您需要根据需要编辑下载的九个补丁(即将蓝色更改为红色)。您可以使用draw 9-patch 工具查看文件,以检查编辑后是否正确定义了文件。
I've edited files using GIMPwith one-pixel pencil tool (pretty easy) but you'll probably use the tool of your own. Here's my customized 9-patch for focused state:
我已经使用GIMP和一像素铅笔工具(非常简单)编辑文件,但您可能会使用自己的工具。这是我为聚焦状态定制的 9-patch :
NOTE:For simplicity, I've used only images for mdpidensity. You'll have to create 9-patchesfor multiple screen densities if, you want the best result on any device. Images for HoloSearchView
can be found in mdpi, hdpiand xhdpidrawable.
注意:为简单起见,我只使用了mdpi密度的图像。如果您想在任何设备上获得最佳效果,则必须为多个屏幕密度创建9 个补丁。Holo 的图像SearchView
可以在mdpi、hdpi和xhdpidrawable 中找到。
Now, we'll need to create drawable selector, so that proper image is displayed based on view state. Create file res/drawable/texfield_searchview_holo_light.xml
with following content:
现在,我们需要创建可绘制的选择器,以便根据视图状态显示正确的图像。创建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>
We'll use the above created drawable to set background for LinearLayout
view that holds text field within SearchView
- its id is android:id/search_plate
. So here's how to do this quickly in code, when creating options menu:
我们将使用上面创建的 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);
}
}
Final effect
最终效果
Here's the screenshot of the final result:
这是最终结果的屏幕截图:
How I got to this
我是怎么做到的
I think it's worth metioning how I got to this, so that this approach can be used when customizing other views.
我认为值得一提的是我是如何做到这一点的,以便在自定义其他视图时可以使用这种方法。
Checking out view layout
检查视图布局
I've checked how SearchView
layout looks like. In SearchView contructorone can find a line that inflates layout:
我检查了SearchView
布局的样子。在SearchView 构造函数中,您可以找到一条夸大布局的行:
inflater.inflate(R.layout.search_view, this, true);
Now we know that SearchView
layout is in file named res/layout/search_view.xml
. Looking into search_view.xmlwe can find an inner LinearLayout
element (with id search_plate
) that has android.widget.SearchView$SearchAutoComplete
inside it (looks like ours search view text field):
现在我们知道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">
Now, we now that the background is set based on current theme's searchViewTextField
attribute.
现在,我们现在根据当前主题的searchViewTextField
属性设置背景。
Investigating attribute (is it easily settable?)
调查属性(是否容易设置?)
To check how searchViewTextField
attribute is set, we investigate res/values/themes.xml. There's a group of attributes related to SearchView
in default Theme
:
为了检查searchViewTextField
属性是如何设置的,我们调查res/values/themes.xml。有一组与SearchView
in default相关的属性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>
We see that for default theme the value is @drawable/textfield_searchview_holo_dark
. For Theme.Light
value is also set in that file.
我们看到默认主题的值为@drawable/textfield_searchview_holo_dark
. ForTheme.Light
值也在该文件中设置。
Now, it would be great if this attribute was accessible through R.styleable, but, unfortunately it's not. For comparison, see other themeattributes which are present both in themes.xmland R.attrlike textAppearanceor selectableItemBackground. If searchViewTextField
was present in R.attr
(and R.stylable
) we could simply use our drawable selector when defining theme for our whole application in XML. For example:
现在,如果这个属性可以通过R.styleable访问,那就太好了,但不幸的是,事实并非如此。为了进行比较,请参阅存在于themes.xml和R.attr 中的其他主题属性,如textAppearance或selectableItemBackground。如果出现在(and ) 中,我们可以在为整个 XML 应用程序定义主题时简单地使用我们的可绘制选择器。例如:searchViewTextField
R.attr
R.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>
What should be modified?
应该修改什么?
Now we know, that we'll have to access search_plate
through code. However, we still don't know how it should look like. In short, we search for drawables used as values in default themes: textfield_searchview_holo_dark.xmland textfield_searchview_holo_light.xml. Looking at content we see that the drawable is selector
which reference two other drawables (which occur to be 9-patches later on) based on view state. You can find aggregated 9-patch drawables from (almost) all version of Android on androiddrawables.com
现在我们知道了,我们必须search_plate
通过代码进行访问。但是,我们仍然不知道它应该是什么样子。简而言之,我们搜索用作默认主题值的可绘制对象:textfield_searchview_holo_dark.xml和textfield_searchview_holo_light.xml。查看内容,我们看到可绘制对象是selector
基于视图状态引用其他两个可绘制对象(稍后出现 9 个补丁)。您可以在androiddrawables.com上找到(几乎)所有 Android 版本的聚合 9-patch drawable
Customizing
定制
We recognize the blue line in one of the 9-patches, so we create local copy of it and change colors as desired.
我们识别出9 个补丁之一中的蓝线,因此我们创建了它的本地副本并根据需要更改颜色。
回答by Abdul Rahman
The above solutions may not work if you are using appcompat library. You may have to modify the code to make it work for appcompat library.
如果您使用的是 appcompat 库,上述解决方案可能不起作用。您可能需要修改代码以使其适用于 appcompat 库。
Here is the working solution for appcompat library.
这是 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);
}
回答by VinceFR
Your onCreateOptionsMenu
method must be:
您的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);
}
where your search item is menu_search
off course
您的搜索项目menu_search
偏离了路线
and here is the searchviewredversion
(this one is the xhdpi version): http://img836.imageshack.us/img836/5964/searchviewredversion.png
这是searchviewredversion
(这是 xhdpi 版本):http://img836.imageshack.us/img836/5964/searchviewredversion.png
回答by David Vávra
The solution above doesn't work with ActionBarSherlock 4.2 and therefore it's not backward compatible to Android 2.x. Here is working code which setups SearchView background and hint text on ActionBarSherlock 4.2:
上述解决方案不适用于 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));
}
回答by Ido
I've tired to do this as well and I'm using v7.
The application was crashed when I tried to grab the searchPlate
via the getIdentifier()
so I done it this way:
我也厌倦了这样做,我正在使用 v7。当我尝试获取searchPlate
via时,应用程序崩溃了,getIdentifier()
所以我这样做了:
View searchPlate = searchView.findViewById(android.support.v7.appcompat.R.id.search_plate);
回答by Suhas Patil
I also faced same problem.I used appcompat v7 library and defined custom style for it. In drawable folder put bottom_border.xml file which looks like this:
我也遇到了同样的问题。我使用了 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>
In values folder styles_myactionbartheme.xml:
在值文件夹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>
I defined custommenu.xml file for displaying menu:
我定义了 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"/>
Your activity should extend ActionBarActivity instead of Activity.
您的活动应该扩展 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);
}
In manifest file:
在清单文件中:
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppnewTheme" >
For more information see here:
Here http://www.jayway.com/2014/06/02/android-theming-the-actionbar/
有关更多信息,请参见此处:
此处http://www.jayway.com/2014/06/02/android-theming-the-actionbar/
回答by Rashid
Update
更新
If you are using AndroidX then you can do it like this
如果您使用的是 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);
}
}
回答by Erol
First, let's create an XML file called search_widget_background.xml, to be used as a drawable, i.e. under drawable directory.
首先,让我们创建一个名为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>
This drawable will be used as the background for our search widget. I set the color to red because that's what you asked for, but you can set it to any color defined by @color tag. You can even modify it further using the attributes defined for shape tag(make rounded corners, do an oval background, etc.).
这个 drawable 将用作我们搜索小部件的背景。我将颜色设置为红色,因为这是您要求的,但您可以将其设置为 @color 标签定义的任何颜色。您甚至可以使用为形状标签定义的属性进一步修改它(制作圆角、制作椭圆背景等)。
Next step is to set the background of our search widget to this one. This can be accomplished by the following:
下一步是将我们的搜索小部件的背景设置为这个。这可以通过以下方式完成:
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);
...
}
回答by M.Raheel
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
这是 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>
回答by vu ledang
I explained in the end of this post with images this is apply for xamarin forms. But i think you can understand it, because it is based on the source code of searchview of android
我在这篇文章的最后用图片解释了这适用于 xamarin 表单。不过我想你能看懂,因为它是基于android的searchview的源代码
How to change searchbar cancel button image in xamarin forms