Android一键换肤原理简述
Posted 怪兽N
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android一键换肤原理简述相关的知识,希望对你有一定的参考价值。
简介
android对应用进行换肤操作,首先要生成一个对应的皮肤包,在要换肤的应用中收集需要换肤的控件,获取皮肤包里的资源,一键换肤时遍历View树,对要换肤的控件进行换肤。下面总结为4个步骤
步骤
1 通过Activity.onCreateView()或 实现LayoutInfaltor.Factory2接口 创建收集可换肤控件
这项工作应该在YourActivity.class
或者BaseActivity.class
或者LifecycleObserver.class
中实现。这个步骤的实现自行搜索。
2 启动或触发换肤的时候加载皮肤包APK的资源
SkinManager.class
public void loaderSkinResources(skinPath){
//反射创建AssestManager并通过路径加载Apk的资源
//通过这个AssestManager获取Resource并用Map缓存
//创建资源管理器(此处不能用:application.getAssets())
AssetManager assetManager = AssetManager.class.newInstance();
// 由于AssetManager中的addAssetPath和setApkAssets方法都被@hide,目前只能通过反射去执行方法
Method addAssetPath = assetManager.getClass().getDeclaredMethod(ADD_ASSET_PATH, String.class);
// 设置私有方法可访问
addAssetPath.setAccessible(true);
// 执行addAssetPath方法
addAssetPath.invoke(assetManager, skinPath);
//==============================================================================
// 如果还是担心@hide限制,可以反射addAssetPathInternal()方法,参考源码366行 + 387行
//==============================================================================
// 创建加载外部的皮肤包(123456.skin,实质是APK)文件Resources(注:依然是本应用加载)
skinResources = new Resources(assetManager, appResources.getDisplayMetrics(), appResources.getConfiguration());
// 根据apk文件路径(皮肤包也是apk文件),获取该应用的包名。兼容5.0 - 9.0(亲测)
skinPackageName = application.getPackageManager().getPackageArchiveInfo(skinPath, PackageManager.GET_ACTIVITIES).packageName;
}
3 通过当前资源包的resourceId获取皮肤包里的资源
SkinManager.class
private int getSkinResourceIds(int resourceId) {
// 优化:如果没有皮肤包或者没做换肤动作,直接返回app内置资源!
if (isDefaultSkin) return resourceId;
// 使用app内置资源加载,是因为内置资源与皮肤包资源一一对应(“netease_bg”, “drawable”)
String resourceName = appResources.getResourceEntryName(resourceId);
String resourceType = appResources.getResourceTypeName(resourceId);
// 动态获取皮肤包内的指定资源ID
// getResources().getIdentifier(“netease_bg”, “drawable”, “com.netease.skin.packages”);
int skinResourceId = skinResources.getIdentifier(resourceName, resourceType, skinPackageName);
}
4 通过applyViews(getWindow().getDecorView())遍历
这个是换肤过程
...........
SkinManager.getInstance().loaderSkinResources(skinPath);
if (themeColorId != 0) {
int themeColor = SkinManager.getInstance().getColor(themeColorId);
StatusBarUtils.forStatusBar(this, themeColor);
NavigationUtils.forNavigation(this, themeColor);
ActionBarUtils.forActionBar(this, themeColor);
}
applyViews(getWindow().getDecorView());
..........................
/**
* 控件回调监听,匹配上则给控件执行换肤方法
*/
protected void applyViews(View view) {
if (view instanceof ViewsMatch) {
ViewsMatch viewsMatch = (ViewsMatch) view;
viewsMatch.skinnableView();
}
if (view instanceof ViewGroup) {
ViewGroup parent = (ViewGroup) view;
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
applyViews(parent.getChildAt(i));
}
}
}
总结
文中所提及的4个步骤是实现换肤的基本原理,当然还有需要很多的优化,也还有兼容性问题,干货已给出啦~~
以上是关于Android一键换肤原理简述的主要内容,如果未能解决你的问题,请参考以下文章
三步实现Android应用内一键换肤,无需重启应用,无需编写多余代码
Android插件化的思考——仿QQ一键换肤,思考比实现更重要!