![enter image description here](https://istack.dev59.com/FwEUY.webp)
很遗憾,无法使用主题、样式和XML继承来设置SearchView
文本字段的样式,就像在ActionBar下拉菜单项的背景中可以做的那样。这是因为selectableItemBackground
被列为可设置的样式在R.stylable
中,而我们感兴趣的searchViewTextField
(主题属性)不是。因此,我们不能轻松地从XML资源中访问它(您将收到一个No resource found that matches the given name: attr 'android:searchViewTextField'
错误)。
因此,正确替换SearchView
文本字段的背景的唯一方法是进入其内部,获取基于searchViewTextField
设置了背景的视图的访问权限,并设置我们自己的背景。
注意: 下面的解决方案仅依赖于SearchView
元素中的id (android:id/search_plate
),因此它比遍历子元素更独立于SDK版本(例如使用searchView.getChildAt(0)
来获取SearchView
内的正确视图),但它并不是绝对可靠的。特别是如果某些制造商决定重新实现SearchView
的内部,并且上述id所对应的元素不存在,那么代码就无法工作。
SearchView
中文本字段的背景是通过九宫格图案声明的,所以我们将采用相同的方式来处理。您可以在Android git存储库的drawable-mdpi目录中找到原始的png图像。我们关注两个图像。一个是当文本字段被选中时的状态(名为textfield_search_selected_holo_light.9.png),另一个是当它没有被选中时的状态(名为textfield_search_default_holo_light.9.png)。
不幸的是,即使您只想自定义聚焦状态,您也需要创建这两个图像的本地副本。这是因为R.drawable中没有textfield_search_default_holo_light
。因此,它不能轻松地通过@android:drawable/textfield_search_default_holo_light
进行访问,该代码可以在下面显示选择器时使用,而不是引用本地可绘制对象。
注意: 我使用了Holo Light主题作为基础,但您也可以使用Holo Dark。在Light和Dark主题之间的选定状态9-patches中似乎没有真正的区别。然而,在默认状态的9-patches上存在差异(请参见Light vs Dark)。因此,可能没有必要为选定状态制作本地副本,对于Dark和Light两种主题都是如此(假设您想处理这两种主题,并使它们看起来与Holo Theme相同)。只需制作一个本地副本并在选择器drawable中使用即可。
现在,您需要根据自己的需求编辑下载的九宫格图案(例如将蓝色更改为红色)。您可以使用draw 9-patch tool查看文件,在编辑后是否正确定义。注意: 为了简单起见,我仅使用了mdpi密度下的图像。 如果您想在任何设备上获得最佳结果,则需要为多个屏幕密度创建9-patches。 Holo SearchView的图像可以在mdpi,hdpi和xhdpi可绘制文件中找到。
现在,我们需要创建一个可绘制选择器,以便根据视图状态显示正确的图像。 创建文件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>
SearchView
中包含文本字段的LinearLayout
视图的背景 - 它的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
,该值也在那个文件中设置。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.xml
和textfield_searchview_holo_light.xml
。查看内容后,我们发现可绘制对象是一个selector
,它引用了两个其他可绘制对象(稍后会变成9-patch),这些对象基于视图状态。你可以在androiddrawables.com上找到几乎所有版本的Android聚合的9-patch可绘制对象。
ActionBar
中显得更低了。这个九宫格是使用这个工具http://android-holo-colors.com/
生成的。 - Etienne Lawlor如果您使用的是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
以上的解决方案不适用于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);
更新
如果您正在使用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);
}
}
我也曾遇到相同的问题。我使用了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>
<?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/
首先,让我们创建一个名为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>
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
内部的一个元素(名为search_plate
)上,而不是SearchView
本身。请参阅我的答案以获取更多详细信息。但是,我必须承认,我还没有尝试使用@(baba tenor)的答案。 - vArDopublic 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 );
........
}
<?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>
我搜索了很多关于编程的内容,最终找到了这个解决方案并且它对我有效!
你可以使用这个方法
如果你使用appcompat,请尝试这个:
ImageView searchIconView = (ImageView) searchView.findViewById(android.support.v7.appcompat.R.id.search_button);
searchIconView.setImageResource(R.drawable.yourIcon);
ImageView searchIconView = (ImageView) searchView.findViewById(androidx.appcompat.R.id.search_button);
searchIconView.setImageResource(R.drawable.yourIcon);
SearchView
背景是不可能的,因为它在R.styleable
中不可用。下面的答案描述了如何在代码中实现。 - vArDo