安卓之Overlay开发主题切换
在安卓开发的主题切换中,有很多种实现方法。如:Skin架构实现主题切换,Overlay机制实现资源替换,项目中Style.xml文件的样式替换,应该还是有些实现资源替换的方法,在这就不叙述了,有些替换的方式,不能引入新的资源文件,只能使用之前已经确定了的样子,比如Style.xml文件。有些替换方式可以导入新的资源信息,比如Overlay机制。Skin架构还没研究透彻,暂时不细说。
Style.xml实现主题切换:
在项目文件中的res/value/theme.xml中设计主题样式:(也有些文件叫:res/value/style.xml)
样式如下:
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.Test" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
<!-- 主题一 -->
<style name="redTheme" parent="AppTheme">
<item name="android:textColor">@color/red</item>
<item name="android:background">@color/red</item>
</style>
<!-- 主题二 -->
<style name="blueTheme" parent="AppTheme">
<item name="android:textColor">@color/red</item>
<item name="android:background">@color/red</item>
</style>
<!-- 主题三 -->
<style name="blackTheme" parent="AppTheme">
<item name="android:textColor">@color/red</item>
<item name="android:background">@color/red</item>
</style>
</resources>
如果出现报错,按alt + enter,对照提示进行错误纠正。完成之后继续下一步。
接着在代码中进行调用:
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_red:
ConstantTools.skinThemeName="red";
setTheme(R.style.redTheme);
recreate();
break;
case R.id.btn_gray:
ConstantTools.skinThemeName="gray";
setTheme(R.style.grayTheme);
recreate();
break;
case R.id.btn_green:
ConstantTools.skinThemeName="green";
setTheme(R.style.greenTheme);
recreate();
break;
case R.id.btn_yellow:
ConstantTools.skinThemeName="yellow";
setTheme(R.style.yellowTheme);
recreate();
break;
}
}
代码中标黄的部分为主要关注点,setTheme(int) :通过style来设置主题,recreate()重绘Activity。该方法会出现短暂黑屏,出现的原因是Activity的重启。同时该方法只能支持apk安装时确定的资源内容,不支持后续的更新。
注:在View开启之前,Theme需要设置完成;
overlay实现主题切换:
overlay有动态和静态之分
静态overlay:称为编译时overlay(SRO),编译时资源就已经覆盖了,一般用在有源码的apk中。比如第一次生成apk的时候。
动态overlay:称为运行时overlay(RRO),当apk在手机中运行时才发生资源覆盖,一般用在无源码的apk中。比如应用已经部署,但后期需要经常更新资源文件的时候。
RRO原理:
应用运行时,通过 getString/getDrawable去调用某个资源,会将资源的resources ID 作为参数传给Framework层。Framework层查找资源时会使用这个resources ID,同时结合当前系统的configuration(分辨率、语言、横竖屏),即通过resources ID 和 configuration,系统首先会调用我们通过RRO添加的资源文件,并根据configuration使用最匹配的资源文件,如果此时没有找到文件,则再调用应用原生的资源文件。其原理如下图所示:
结合上图可以看出应用只是负责提供resource ID,系统会根据configuration中的配置(语言、分辨率等)去获取适当的资源来加载,这是两个不连续和独立的过程。RRO就发生在系统检索资源的过程中,而应用使用资源的接口不变。因此,通过RRO无需对应用做任何修改。
overlay使用前提:
资源所在路径必须与overlay下资源路径完全相同。
overlay使用:
在android studio中,想要使用overlay资源替换机制,需要先创建替换资源的模块。在创建的模块中,修改AndroidManifest.xml文件中的内容,内容大体如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="当前模块的包名">
<overlay android:targetPackage="需要替换资源的包名" android:priority="1"/>
<application
android:hasCode="当先模块是否有代码块" />
</manifest>
priority属性用来设置当前替换资源的优先级,范围为0-9999;
overlay生成的apk需要与原apk的包签名相同。overlay同Target Apk必须保存统一的资源ID,系统或应用或其他自定义的资源ID。还需要在AndroidManifest.xml文件中声明权限:
<uses-permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES"
tools:ignore="ProtectedPermissions" />
检查权限的举动
在android studio中设置包签名的两种方法:
1、在对应app模块的build.gradle中添加如下代码:
signingConfigs {
main {
storeFile file("./platform.keystore") //签名文件路径
storePassword "密码"
keyAlias "别名"
keyPassword "密码"
}
}
buildTypes {
debug {
minifyEnabled false
signingConfig signingConfigs.main
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
release {
minifyEnabled false
signingConfig signingConfigs.main
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
黄色标记为签名配置设置;
2、android studio--->Build--->Generate Signed Bundle or APK --->APK----->将包签名文件导入。
参考文献:https://blog.csdn.net/u013795543/article/details/81050893?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_antiscanv2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_antiscanv2&utm_relevant_index=2