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

我正在尝试更改 Android 操作栏 searchview 小部件中的绘图工具。

目前的情况是这样的: enter image description here

但是我需要把蓝色的背景改成红色。

除了滚动我自己的搜索小部件,我尝试了很多方法,但似乎都不管用。

谁能告诉我怎么改变现状?

81084 次浏览

首先,让我们创建一个名为 search _ widget _ backound.XML 的 XML 文件,用作可绘制目录,即可绘制目录下。

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

这个绘图工具将用作我们的搜索小部件的背景。我将颜色设置为红色,因为这是您要求的,但是您可以将其设置为@color 标记定义的任何颜色。您甚至可以使用为 形状标签定义的属性进一步修改它(使用圆角、椭圆背景等)。

下一步是将我们的搜索小部件的背景设置为这个。这可以通过以下方式实现:

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

介绍

不幸的是,没有办法设置 SearchView文本字段样式使用主题,样式和继承在 XML 作为您的 可以在 ActionBar 下拉列表中处理项目的背景。这是因为 R.stylable中的 selectableItemBackground 被列为可设计风格,而 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 仓库可绘制 -mdpi目录中找到原始的 图像。我们对两张图片感兴趣。一个表示选择文本字段时的状态(命名为 Textfield _ search _ select _ holo _ light.9. png) ,另一个表示不选择文本字段时的状态(命名为 Textfield _ search _ default _ holo _ light.9. png)。

不幸的是,您必须创建这两个映像的本地副本,即使您只想定制 集中注意力状态。这是因为 textfield_search_default_holo_light不存在于 可以画中。因此,它不容易通过 @android:drawable/textfield_search_default_holo_light访问,这可以在下面所示的选择器中使用,而不是引用本地绘制。

注意: 我使用 全息光主题作为基础,但是你也可以使用 你好,黑暗灯光黑暗主题之间的 选定的州9补丁似乎没有真正的区别。然而,在 默认状态的9个补丁中存在差异(参见 灯光Dark)。因此,对于 黑暗你好,黑暗0主题,可能不需要为 选定的州制作9-补丁的本地副本(假设您想同时处理这两个主题,并使它们看起来与 你好,黑暗1相同)。只需制作一个本地副本,并在 你好,黑暗2中对两个主题都使用它。

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

我曾经用一像素铅笔工具(非常简单)编辑过使用 GIMP的文件,但是你可能会使用你自己的工具。这是我为 集中状态定制的9补丁:

enter image description here

注意: 为了简单起见,我只使用了 Mdpi密度的图像。如果您希望在任何设备上获得最佳效果,那么您必须为多屏幕密度创建 9-patches你好 SearchView的图像可以在 MdpiHdpixhdpi中找到。

现在,我们需要创建可绘制的选择器,以便根据视图状态显示适当的图像。创建包含以下内容的文件 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);
}


}

最终效果

下面是最终结果的截图:

enter image description here

我怎么会变成这样

我认为值得一提的是我是如何做到这一点的,以便在定制其他视图时可以使用这种方法。

检查视图布局

I've checked how SearchView layout looks like. In SearchView 构造函数 one can find a line that inflates layout:

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 风格访问,那就太好了,但是,不幸的是它不能。为了进行比较,请参阅 Themes.xmlR.attr中存在的其他 theme属性,如 textAppearance背景。如果 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。然而,我们仍然不知道它应该是什么样子。简而言之,我们搜索默认主题 Textfield _ searchview _ holo _ dark. xmlTextfield _ searchview _ holo _ light. xml中作为值使用的绘图。看看内容,我们发现可绘制的是 selector,它引用了另外两个基于视图状态的可绘制内容(稍后会出现9个补丁)。你可以在 androiddrawables.com上找到(几乎)所有 Android 版本的聚合9补丁绘图工具

定制

我们识别 九块补丁中的一块中的蓝线,所以我们创建它的本地副本并根据需要改变颜色。

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

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

如果使用 appcompat 库,上述解决方案可能无法工作。您可能需要修改代码以使其适用于 appcompat 库。

Here is the working solution for appcompat library.

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

我也面临同样的问题。我使用 appcompat v7库并为它定义了自定义样式。 在可绘制文件夹中放置 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>

在 value 文件夹 style _ 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" >

欲了解更多信息,请点击这里:
Here 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>

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:

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

我在这篇文章的最后用图片来解释 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 形式

更新

如果你正在使用 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);
}
}

如果你像这样对 Searchview 进行充气,那么你可以像下面这样通过 style.xml 定制这个 Searchview。

<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="searchViewStyle">@style/SearchView.ActionBar</item>
</style>


<style name="SearchView.ActionBar" parent="Widget.AppCompat.SearchView.ActionBar">
<item name="queryBackground">@drawable/drw_search_view_bg</item>
<item name="searchHintIcon">@null</item>
<item name="submitBackground">@null</item>
<item name="closeIcon">@drawable/vd_cancel</item>
<item name="searchIcon">@drawable/vd_search</item>
</style>

我挖掘了很多,最后我找到了这个解决方案,它适合我!
你可以用这个

如果你使用 appcompat,试试这个:

ImageView searchIconView = (ImageView) searchView.findViewById(android.support.v7.appcompat.R.id.search_button);
searchIconView.setImageResource(R.drawable.yourIcon);

如果你使用 androidx,试试这个:

ImageView searchIconView = (ImageView) searchView.findViewById(androidx.appcompat.R.id.search_button);
searchIconView.setImageResource(R.drawable.yourIcon);

它将更改默认的 serchview 图标。

希望能有帮助!