简介: 有关于Android 实现应用内动态切换主题的常用方式有两种
通过Theme切换主题 通过AssetManager切换主题 本文主要介绍通过Theme切换主题。
通过Theme切换主题
Android 通过在activity中使用 setTheme()函数来设置背景样式,通过加载styles.xml里的样式来设置Android 应用的主题。(注意:需要在 setContentView(R.layout.activity_main);之前调用setTheme)
在开始制作主题之前我们先看下这张图 通过这张图我们可以了解到不同的字段代表的是哪一块的颜色,例如:
colorPrimary 代表的是 App Bar 的颜色。 colorPrimaryDark 代表的是状态栏的背景色。 我们也可以自己定制布局控件的颜色:
1. 在values文件夹下创建attr.xml ,在attr.xml写入属性名
4. 在styles.xml文件下自定义主题样式 在这里写个例子示范。
parent 是指继承的主题风格, 常见的主题风格有:以下这些: android:theme="@android:style/Theme.Dialog" 将一个Activity显示为能话框模式 android:theme="@android:style/Theme.NoTitleBar" 不显示应用程序标题栏 android:theme="@android:style/Theme.NoTitleBar.Fullscreen" 不显示应用程序标题栏,并全屏 android:theme=“Theme.Light” 背景为白色 android:theme=“Theme.Light.NoTitleBar” 白色背景并无标题栏 android:theme=“Theme.Light.NoTitleBar.Fullscreen” 白色背景,无标题栏,全屏 android:theme=“Theme.Black” 背景黑色 android:theme=“Theme.Black.NoTitleBar” 黑色背景并无标题栏 android:theme=“Theme.Black.NoTitleBar.Fullscreen” 黑色背景,无标题栏,全屏 android:theme=“Theme.Wallpaper” 用系统桌面为应用程序背景 android:theme=“Theme.Wallpaper.NoTitleBar” 用系统桌面为应用程序背景,且无标题栏 android:theme=“Theme.Wallpaper.NoTitleBar.Fullscreen” 用系统桌面为应用程序背景,无标题栏,全屏 android:theme=“Translucent” 半透明 android:theme=“Theme.Translucent.NoTitleBar” 半透明、无标题栏 android:theme=“Theme.Translucent.NoTitleBar.Fullscreen” 半透明、无标题栏、全屏 android:theme=“Theme.Panel”
5. 实现读取配置文件设置主题
private void setBaseTheme() { SharedPreferences sharedPreferences = getSharedPreferences( "com.example.test_preferences", MODE_PRIVATE); String themeType = sharedPreferences.getString("theme_type", "蓝色主题"); int themeId; switch (themeType) { case "蓝色主题": themeId = R.style.blueTheme; break; case "粉色主题": themeId = R.style.pinkTheme; break; case "彩色主题": themeId = R.style.AppTheme; break; default: themeId = R.style.blueTheme; } setTheme(themeId); } 使用SharedPreferences 来读取文件。根据读取的参数来设置主题 再次提醒,需要写在setContentView(R.layout.activity_main);之前
Android之基于AssetManager实现换肤方案
AssetManager的addAssetPath负责将另一个apk的资源文件加载进当前应用,这里由于是api隐藏方法,采用反射方式调用。
查看addAssetPath方法注释,允许传递的路径为资源目录或者zip文件。
/**
* Add an additional set of assets to the asset manager. This can be
* either a directory or ZIP file. Not for use by applications. Returns
* the cookie of the added asset, or 0 on failure.
* {@hide}
*/
通过实例化的AssetManager对象,生成插件包对应的Resources对象,拿到该对象即可操作插件包的相关资源文件。
private Resources pluginRes;//插件Resource对象
private String pluginApkPackageName;//插件Apk的包名
public ResPluginOnAssetManagerPattern initManager(Context curContext, String pluginApkPath) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, PackageManager.NameNotFoundException, ClassNotFoundException {
AssetManager assetManager = AssetManager.class.newInstance();
Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
addAssetPath.invoke(assetManager, pluginApkPath);
Resources curAppRes = curContext.getResources();
pluginRes = new Resources(assetManager, curAppRes.getDisplayMetrics(), curAppRes.getConfiguration());
pluginApkPackageName = UtilsSystem.getPackageNameThroughApkPath(curContext, pluginApkPath);
return this;
}
想要获取插件包的资源,可以通过以下方式引用(这里仅给出string以及drawable的调用方式,其他资源类似):
/**
* 获取ResID
*
* @param resName
* @param resType
* @return
*/
private int getResId(String resName, String resType) {
if (pluginRes != null && !UtilsString.isEmptyBaseTrim(pluginApkPackageName)) {
return pluginRes.getIdentifier(resName, resType, pluginApkPackageName);
}
return -1;
}
@Override
public String getString(String resName) {
return pluginRes.getString(getResId(resName, "string"));
}
@Override
public Drawable getDrawable(String resName) {
return pluginRes.getDrawable(getResId(resName, "drawable"));
}
源码地址:https://github.com/xiaoxuan948/AndroidUnityLab/tree/master/unity_base_dev_helper/src/main/java/com/coca/unity_base_dev_helper/plugin
参考文章:https://blog.csdn.net/qq_36674643/article/details/90546926