我正在try 更改Android actionbar searchview小部件中的drawable.

现在看起来是这样的:

但我需要把蓝色背景改成红色.

除了滚动我自己的搜索小部件,我已经try 了很多方法,但似乎没有任何效果.

有人能给我指个正确的方向来改变这一点吗?

推荐答案

简介

遗憾的是,您无法使用XML中的主题、样式和继承将SearchView文本字段样式设置为can do with background of items in ActionBar dropdown.这是因为R.stylable中的selectableItemBackgroundis listed as styleable,而searchViewTextField(我们感兴趣的主题属性)不是.因此,我们不能从XML资源中轻松地访问它(您将得到一个No resource found that matches the given name: attr 'android:searchViewTextField'错误).

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

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

NOTE:下面的解决方案只依赖于SearchView中元素的id(android:id/search_plate),因此它比子遍历(例如,使用searchView.getChildAt(0)SearchView中获得正确的视图)更独立于SDK版本,但它不是防弹的.尤其是如果一些制造商决定重新实现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).

不幸的是,即使只想自定义focused个状态,也必须创建两个图像的本地副本.这是因为R.drawable中没有textfield_search_default_holo_light.因此,它不容易通过@android:drawable/textfield_search_default_holo_light访问,@android:drawable/textfield_search_default_holo_light可以在下面所示的 Select 器中使用,而不是引用本地drawable.

我使用的是Holo Light主题作为基础,但是你也可以用Holo Dark做同样的事情.在selected state个9补丁中,Light个主题和Dark个主题似乎没有真正的区别.但是,default state的9个补丁有所不同(参见LightDark).因此,可能不需要为selected stateDarkLight主题制作9个补丁的本地副本(假设您想同时处理这两个主题,并使它们看起来都与Holo Theme中的相同).只需创建一个本地副本,并在selector drawable中将其用于两个主题.

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

我已经用单像素的铅笔工具用GIMP编辑过文件(相当简单),但您可能会使用自己的工具.以下是我为focused state定制的9个补丁:

在此处输入图像描述

NOTE:为了简单起见,我只使用了mdpi密度的图像.如果你想在任何设备上获得最佳效果,就必须为多个屏幕密度创建9-patches.Holo SearchView的图像可以在mdpihdpixhdpi中找到.

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

}

最终效果

以下是最终结果的截图:

在此处输入图像描述

我是怎么做到的

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

签出视图布局

我已经判断了SearchView的布局.在SearchView contructor中,人们可以找到一条可以使布局inflating 的线:

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等于is also set in that file.

现在,如果这个属性可以通过R.styleable访问就好了,但不幸的是,它不是.要进行比较,请参见themes.xmlR.attr中的其他theme个属性,如textAppearanceselectableItemBackground.如果R.attr(和R.stylable)中有searchViewTextField,那么在用XML为整个应用程序定义主题时,我们可以简单地使用可绘制 Select 器.例如:

<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补丁可绘制内容

定制

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

Android相关问答推荐

超过Unity+Android磁贴内存限制,部分内容可能无法绘制

Android Compose Lazy柱形实时UI更改

Android:微调:在代码中设置ArrayAdapter不希望调用On ItemSelected,仅当用户单击微调时调用

默认调度程序是否在协程中使用共享线程池?

如何判断堆肥是否为空?

弹出导航堆栈后,Compose 无法访问 Hilt View Model

在 kotlin 上向适配器添加绑定视图功能

Jetpack Compose 中的用户在线指示器

Android 访问任意公共目录

为什么我收到这个错误我需要安装 android studio

当 Firebase Firestore 发生变化时,Kotlin ViewModel 不会更新

设置背景图片组成Column

AttributionSource 需要 android.permission.BLUETOOTH_SCAN 权限的问题

为什么项目捕获对象给我在 Compose 中找不到参考

Android collectAsStateWithLifecycle() 不在可组合内部收集

如何在 Jetpack Compose 中禁用 Horizo​​ntalPager 的分页动画

如何关闭可组合对话框?

如何在 Jetpack compose 中将 Canvas 中的文本居中?

可扩展性 Qt 5.15 Android

Firebase Crashlytics 缩小 R8 Android