暗夜模式续
之前写过一篇笨拙的方式实现暗夜模式,但是当真正去适配的时候发现简直恶心至极;然后想通过一些方式可以把笨拙的方式变得优雅;
之前实现暗夜模式的快速通道,这篇文章在基于这个基础上优化而来
目录
背景
优化步骤
OK,思路有了下面是具体的实现方式;
自定义View继承系统原有控件
BaseDarkLightModeAttrProcessor 代码
View自己是遍历改变子View模式
背景
简述下为什么选择自己更换颜色值,图片的方式。在实现上发现采用系统的方式,Activity必须重启一次。而我们的框架是单Activity+N Fragment的方式,是为了达到只有一个地图UI甲方要求,但是这样就需要以Fragment Tag为key值缓存缓存地图上线路、marker信息;所以Activity重启所要做的适配难度直接让我放弃了系统方式。
那么现在到了真正适配暗夜模式的开发阶段,发现适配一个界面就等于重构一次xml,而且代码量成指数级上升;
优化步骤
第一步优化:
当时想要怎么优化,脑海里第一个念头就是自定义View 继承 系统原有控件;设置定义属性 在xml中就可以定义白天颜色值,暗夜颜色值;然后外部传入当前模式,达到减少Fragment上的代码量。
第二步优化:
发现这样还是有必须在Fragment中找到所有需要切换的控件id,然后指定模式,况且还有很多是没有预设ID的View;所以就想到了可以让View自己是遍历改变子View模式;这样在设置模式的时候一行代码即可。
OK,思路有了下面是具体的实现方式;
自定义View继承系统原有控件
public class DarkConstraintLayout extends ConstraintLayout implements DarkLightMode {BaseDarkLightModeAttrProcessor<TjConstraintLayout> processor;public TjConstraintLayout(@NonNull Context context) {super(context);init(context, null, 0);}public DarkConstraintLayout(@NonNull Context context, @Nullable AttributeSet attrs) {super(context, attrs);init(context, attrs, 0);}public DarkConstraintLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context, attrs, defStyleAttr);}private void init(Context context, AttributeSet attrs, int defStyleAttr) {processor = new BaseDarkLightModeAttrProcessor<TjConstraintLayout>(context, attrs, defStyleAttr, this);}/*** 切换模式** @param darkMode 是否深色模式*/@Overridepublic void processMode(boolean darkMode) {LogUtils.e("TjConstraintLayout processMode" + darkMode);processor.process(darkMode);}}
在init()方法中初始化 BaseDarkLightModeAttrProcessor 去统一控制
BaseDarkLightModeAttrProcessor 代码
public class BaseDarkLightModeAttrProcessor<T extends View> {protected T targetView;protected Drawable lightBackground;protected Drawable darkBackground;protected int lightBackgroundColor = -1;protected int darkBackgroundColor = -1;private boolean darkMode = false;public BaseDarkLightModeAttrProcessor(Context context, AttributeSet attrs, int defStyle, T targetView) {this.targetView = targetView;if (attrs != null) {// 所有需要适配黑夜模式的View样式属性全部定义在NightMode样式下,在xml中定义了,但View不识别的样式会被忽略TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.DarkLightMode, defStyle, 0);parseAttrs(typedArray);typedArray.recycle();process(darkMode);}}/*** 设置浅色背景** @param lightBackground 浅色背景*/public void setLightBackground(Drawable lightBackground) {this.lightBackground = lightBackground;}/*** 设置深色背景** @param darkBackground 深色背景*/public void setDarkBackground(Drawable darkBackground) {this.darkBackground = darkBackground;}public Drawable getLightBackground() {return lightBackground;}public Drawable getDarkBackground() {return darkBackground;}/*** 设置浅色背景颜色** @param color 浅色背景颜色*/public void setLightBackgroundColor(int color) {this.lightBackgroundColor = color;}/*** 设置深色背景颜色** @param color 深色背景颜色*/public void setDarkBackgroundColor(int color) {this.darkBackgroundColor = color;}/*** 设置是否深色模式** @param darkMode 是否深色模式*/public void setDarkMode(boolean darkMode) {this.darkMode = darkMode;}public boolean isDarkMode() {return darkMode;}protected void parseAttrs(TypedArray typedArray) {lightBackground = typedArray.getDrawable(R.styleable.DarkLightMode_lightBackground);darkBackground = typedArray.getDrawable(R.styleable.DarkLightMode_darkBackground);lightBackgroundColor = typedArray.getColor(R.styleable.DarkLightMode_lightBackgroundColor, -1);darkBackgroundColor = typedArray.getColor(R.styleable.DarkLightMode_darkBackgroundColor, -1);}public final void process() {process(darkMode);}public void process(boolean darkMode) {this.darkMode = darkMode;if (this.darkMode) {if (darkBackground != null) {if (Build.VERSION.SDK_INT < 16) {targetView.setBackgroundDrawable(darkBackground);} else {targetView.setBackground(darkBackground);}}if (darkBackgroundColor != -1) {targetView.setBackgroundColor(darkBackgroundColor);}} else {if (lightBackground != null) {if (Build.VERSION.SDK_INT < 16) {targetView.setBackgroundDrawable(lightBackground);} else {targetView.setBackground(lightBackground);}}if (lightBackgroundColor != -1) {targetView.setBackgroundColor(lightBackgroundColor);}}}}
当然不是针对的自定义View,或者别的独特的系统控件,可以继承 BaseDarkLightModeAttrProcessor 单独去处理。这里就不贴代码了
View自己是遍历改变子View模式
public static void processAllViewDarkMode(View view, boolean darkMode) {if (view instanceof DarkLightMode) {((DarkLightMode) view).processMode(darkMode);}if (view instanceof ViewGroup) {ViewGroup viewGroup = (ViewGroup) view;for (int i = 0; i < viewGroup.getChildCount(); i++) {View childView = viewGroup.getChildAt(i);if (childView instanceof DarkLightMode) {((DarkLightMode) childView).processMode(darkMode);}processAllViewDarkMode(childView, darkMode);}}}
使用
@Overridepublic void onNightModeChanged(boolean isDarkMode) {super.onNightModeChanged(isDarkMode);viewModel.setDarkMode(commonNavigator, isDarkMode);DarkLightModeUtil.processAllViewDarkMode(binding.getRoot(), isDarkMode);}
原来需要上百行的代码,简简单单一行代码就可以实现。当然还可以有一些拓展 就不一一赘述,
最后感谢我的领导,让我学会了思考,而不是一味地做代码重复操作。