主题中定义具体的资源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。
- <Button
- android:layout_width="match_parent"
- android:layout_height="50dp"
- android:layout_marginTop="10dp"
- android:background="#ffffff"
- android:gravity="center"
- android:tag="text=string/test_string|textColor=color/skin_test_color"
- android:text="@string/test_string"
- android:textColor="?attr/module_color" />
换肤的时候遍历视图树。
然后就是与方案二中一样,读取皮肤包资源咯。
方案特点:侵入性较低,但是使用、改造成本比较高。
相关原理参考: