文章目录
前言
做了一个主题切换框架,在这里毛遂自荐一下,小伙伴们看看有没有用,欢迎批评指正。
项目地址:https://github.com/l0neman/ThemeFramework
下面是项目的 README.md 自述文件。
ThemeFramework
Android 即时主题切换框架
核心是基于属性(attrs.xml 中配置)可根据所属主题(themes.xml 中配置)的不同,获得每种主题下的对应资源。
使用形式是在布局中配置对应的主题属性,然后一行代码一键切换主题。
PS:
欢迎小伙伴们提出建议和贡献代码。
主要特点
- 低侵入性,不提供强制使用的控件
只提供主题属性以供布局中配置,可通过正则表达式搜索然后批量移除,不移除也不会对程序逻辑造成任何影响。
- 高扩展性,易于支持新的 View
只需提供自定义主题属性和将属性资源设置给 View 的逻辑,以框架开发者和框架使用者的角度对支持的 View 类型进行扩展均非常方便。
要求:
必须使用 androidx 提供的 AppCompatActivity
和 Fragment
(几乎是 Android 开发必选项),因为它们都是 LifecycleOwner
的实现类,框架可以方便的监听组件的生命周期,便于在组件销毁时自动释放资源,避免使用者手动处理资源。
待优化:
- 提供的主题属性 Android Studio 不会自动提示,目前主题属性的命名是在对应 View 的原始属性之前添加
tf_
前缀,所以较易书写; - 主题属性在 Android Framework 提供的原生控件标签中会报红,因为 Android Studio 认为主题属性并非控件本身属性,虽然不影响编译,但是会令人不舒服。例如:
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:textColor="?attr/appTextColor"
app:tf_background="selectableItemBackground"
app:tf_textColor="appTextColor" />
<!-- 最后两行 IDE 会显示红色 -->
建议解决办法:
- 使用相应的
androidx.appcompat.widget.AppCompatXXX
组件替代,就不会报红了,因为 Android Studio 认为 androidx Android Studio 允许使用未知属性。目前几乎所有的控件都有对应的 androidx 兼容性组件,除了 ListView、ProgressBar 零星组件;
<androidx.appcompat.widget.AppCompatButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:textColor="?attr/appTextColor"
app:tf_background="selectableItemBackground"
app:tf_textColor="appTextColor" />
- 或者加入
tools:ignore="MissingPrefix"
属性即可去除警告。
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:textColor="?attr/appTextColor"
app:tf_background="selectableItemBackground"
app:tf_textColor="appTextColor"
tools:ignore="MissingPrefix" />
快速开始
- 定义应用主题和主题属性
首先确定你的应用支持几种主题,例如支持白天主题和夜间主题,那么需要准备这两种主题所需的主题资源,通常是 color 和 drawable 资源。
例如,提供字体颜色和设置图标两个主题资源,那么首先在 attrs.xml 中自定义主题资源属性:
<!-- attrs.xml -->
<!-- 字体颜色,color 类型 -->
<attr name="appTextColor" format="color" />
<!-- 设置图标,drawable 类型 -->
<attr name="ic_settings" format="reference" />
然后在 themes.xml
定义每种主题,以及主题包含的主题资源属性对应的具体资源:
<!-- themes.xml -->
<!-- 父主题 -->
<style name="BaseTheme.Light" parent="Theme.AppCompat.Light.NoActionBar"></style>
<style name="BaseTheme.Dark" parent="Theme.AppCompat.NoActionBar"></style>
<!-- 夜间主题,白色文本和图标 -->
<style name="AppTheme.Black" parent="BaseTheme.Dark">
<item name="appTextColor">#FFFFFF</item>
<item name="ic_settings">@drawable/ic_baseline_settings_white_24</item>
</style>
<!-- 白天主题,黑色文本和图标 -->
<style name="AppTheme.White" parent="BaseTheme.Light">
<item name="appTextColor">#000000</item>
<item name="ic_settings">@drawable/ic_baseline_settings_black_24</item>
</style>
主题资源准备完毕,下面可以进行主题切换了。
- 框架初始化
首先在应用的 Application
类的 onCreate
方法中初始化框架。
通常当应用的用户本次切换主题后,下次打开应用需要保证应用处于用户最后一次切换的主题,初始化就是为了设置用户最后一次的主题,同时保证每个 Activity 创建时都使用了当前的主题。
public class MyApp extends Application {
@Override public void onCreate() {
super.onCreate();
// R.style.AppTheme 为应用首次启动默认的主题
ThemeFramework.getInstance().setup(this, R.style.AppTheme);
}
}
- 配置主题属性
下面以 TextView 和 ImageView 为例,实现不同主题下的文字颜色和图标。
在应用的 Activity 的布局中进行如下配置:
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="?attr/appTextColor"
app:tf_textColor="appTextColor" />