MD3——SearchView自定义背景
介绍
官方描述:
SearchView组件提供了一个全屏搜索视图的实现,该视图可用于显示返回导航、搜索提示和文本、菜单项以及搜索建议和结果。它还带有一个清晰的文本按钮,根据用户是否输入文本显示和隐藏。
效果如下:
可用属性如下:
| Element | Attribute | Related method(s) | Default value | |
|---|---|---|---|---|
| Search text appearance | android:textAppearance | setTextAppearance getTextAppearance | @style/TextAppearance.Material3.SearchBar | |
| Search text | android:text | setText getText | null | |
| Search hint | android:hint | setHint getHint | null | |
| Color | app:backgroundTint | -- | ?attr/colorSurfaceContainerHigh | |
| Flag for navigation icon | app:hideNavigationIcon | -- | true | |
Flag for DrawerArrowDrawable | app:useDrawerArrowDrawable | -- | false | |
| Flag for soft keyboard | app:autoShowKeyboard | -- | true | |
需求
需要修改这个背景色,并且是动态修改。尝试过修改app:backgroundTint ,但是不起作用,所以在SearchView里翻呀翻,最后也算是找到了解决办法。
分析SearchVIew
可以看到SearchView里有一个backgroundView,不难知道这个就是我们需要修改颜色的View
// SearchView
...
final View backgroundView;
...
// 修改颜色的地方
private void setUpBackgroundViewElevationOverlay(float elevation) {
if (elevationOverlayProvider == null || backgroundView == null) {
return;
}
int backgroundColor =
elevationOverlayProvider.compositeOverlayWithThemeSurfaceColorIfNeeded(elevation);
backgroundView.setBackgroundColor(backgroundColor);
}
找到地方就好办了,直接拷贝一个SearchView,然后改成自己想要的颜色即可
注意:名字不要和原来一样,会冲突;然后
SearchView里有一个searchViewAnimationHelper参数是SearchView,所以我们也需要拷贝一份把里面的SearchView换成CustomSearchView
看下效果:
改进
虽然成功改了颜色,但是和原来效果不一样呀,原来的颜色是基于colorPrimary的,并且也不是这样的纯色,对比下之前的:
可以看到似乎是
colorPrimary的颜色叠加了白色,那我们就继续看SearchView,可以知道颜色处理肯定是在这行代码:
int backgroundColor =
elevationOverlayProvider.compositeOverlayWithThemeSurfaceColorIfNeeded(elevation);
那就继续看这个方法的实现:
// ElevationOverlayProvider
...
// 看到这个colorSurface就知道他的颜色是白/黑
// 根据主题变换,证实了之前的猜想
@ColorInt
public int compositeOverlayWithThemeSurfaceColorIfNeeded(float elevation) {
return compositeOverlayIfNeeded(colorSurface, elevation);
}
...
@ColorInt
public int compositeOverlayIfNeeded(@ColorInt int backgroundColor, float elevation) {
if (elevationOverlayEnabled && isThemeSurfaceColor(backgroundColor)) {
return compositeOverlay(backgroundColor, elevation);
} else {
return backgroundColor;
}
}
...
// 关键代码实现
@ColorInt
public int compositeOverlay(@ColorInt int backgroundColor, float elevation) {
float overlayAlphaFraction = calculateOverlayAlphaFraction(elevation);
int backgroundAlpha = Color.alpha(backgroundColor);
int backgroundColorOpaque = ColorUtils.setAlphaComponent(backgroundColor, 255);
int overlayColorOpaque =
MaterialColors.layer(backgroundColorOpaque, elevationOverlayColor, overlayAlphaFraction);
if (overlayAlphaFraction > 0 && elevationOverlayAccentColor != Color.TRANSPARENT) {
int overlayAccentColor =
ColorUtils.setAlphaComponent(elevationOverlayAccentColor, OVERLAY_ACCENT_COLOR_ALPHA);
overlayColorOpaque = MaterialColors.layer(overlayColorOpaque, overlayAccentColor);
}
return ColorUtils.setAlphaComponent(overlayColorOpaque, backgroundAlpha);
}
这里的elevationOverlayColor和elevationOverlayAccentColor默认是和colorPrimary是同色,到这里就已经知道如何修改颜色了,具体内部做了什么计算就不管了,在我们的SearchView里添加一个修改背景色的方法,把上面compositeOverlay方法的关键实现拷贝过来:
public void setBackgroundViewColor(@ColorInt int color) {
int backgroundColor = MaterialColors.getColor(getContext(), R.attr.colorSurface, Color.WHITE);
float elevation = getOverlayElevation();
float overlayAlphaFraction = elevationOverlayProvider.calculateOverlayAlphaFraction(elevation);
int backgroundAlpha = Color.alpha(backgroundColor);
int backgroundColorOpaque = ColorUtils.setAlphaComponent(backgroundColor, 255);
int overlayColorOpaque =
MaterialColors.layer(backgroundColorOpaque, color, overlayAlphaFraction);
if (overlayAlphaFraction > 0 && color != Color.TRANSPARENT) {
int overlayAccentColor =
ColorUtils.setAlphaComponent(color, (int) Math.round(0.02 * 255));
overlayColorOpaque = MaterialColors.layer(overlayColorOpaque, overlayAccentColor);
}
int overlayColor = ColorUtils.setAlphaComponent(overlayColorOpaque, backgroundAlpha);
backgroundView.setBackgroundColor(overlayColor);
}
// 调用(kotlin)
binding.colorSearchView.setBackgroundViewColor(themeColor)
这里要注意: elevationOverlayColor和elevationOverlayAccentColor替换成我们需要设置的颜色(color),原因前面分析过了哈。如果需要让颜色更深一点,可以修改elevation的值,看看效果吧:
补充:如何需要设置背景图片也是可以的
backgroundView.setBackgroundResource(int resid)
总结
为了改这个,网上一顿查,愣是没找到解决办法,还好解决了,不然我可能直接强行改成黑白了