尝试了一下 3 个换肤方案,Demo 送上
主题中定义具体的资源style,我们需要在setContentView之前设置我们的主题即可。
override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)if ("default" != getSp(this, "theme")) {setTheme(R.style.Theme_Style1)}setContentView(R.layout.activity_demo1_theme)
}
缺点:需要重新创建Activity才会生效,会导致界面状态丢失
既然使用setTheme方案都需要重新创建Activity,那么其实我们也可以自己找到所有需要换肤的控件,然后手动设置就可以完成换肤了,这种方案代表框架Android-Skin-Loader,不过可惜很久没有更新了。
大致步骤如下:
1、收集需要换肤的控件以及属性
2、制作皮肤包
3、读取皮肤包
4、动态刷新控件
5、其他:支持手动设置属性,手动添加控件
其实我们查看LayoutInflater#createViewFromTag源码即可知道,系统在创建View之前会使用LayoutInflater#tryCreateView去看看外部是不是想自己创建控件,具体会调用外部设置的Factory2#onCreateView,如果返回null,则系统去创建,那么我们就可以在这个里面解析对应控件的属性,如果是支持换肤的属性,则创建自己手动控件,并保存。
方案特点:
1、自动化程度比较高,改造成本也低。
2、存在一定侵入性。
此方案其实与方案二的步骤非常相似,唯一不同的地方在于,方案二使用了layoutFactory去获取所有支持换肤的控件,本方案则是在控件上设置tag的方式来标记,方案二在创建布局的时候收集所有控件,性能上存在部分损耗,使用tag则是在换肤的时候,遍历控件树去修改属性。代表方案为AndroidChangeSkin。https://github.com/hongyangAndroid/AndroidChangeSkin
在xml中使用tag。
换肤的时候遍历视图树。
然后就是与方案二中一样,读取皮肤包资源咯。
方案特点:侵入性较低,但是使用、改造成本比较高。
相关原理参考:
换肤、全局字体替换、无需编写shape、selector 的原理Factory小结