Android实现换肤思路整理
Android实现换肤思路整理
- 整体思路总结:
- 1.获取APP 的Resources对象
- 2.使用反射创建AssetManager对象
- 3.根据设备的显示器信息和配置,创建Resource对象
- 4.使用PackageManager,根据皮肤包路径获取皮肤包包名
- 5.注册ActivityLifeCycle,监测activity oncreate回调,配置自定义的layoutInflater对象,自定义layoutinflater对象接管View 的创建过程,在创建View时统计需要替换属性的view
- 6.触发换肤动作,使用resource对象获取皮肤包属性值,设置到目标view
- 7.实现功能
整体思路总结:
1.获取APP 的Resources对象
mAppResources = context.getResources();
2.使用反射创建AssetManager对象
//反射创建AssetManager 与 Resource
AssetManager assetManager = AssetManager.class.newInstance();
//资源路径设置 目录或压缩包
Method addAssetPath = assetManager.getClass().getMethod("addAssetPath",
String.class);
addAssetPath.invoke(assetManager, skinPath);
3.根据设备的显示器信息和配置,创建Resource对象
//根据当前的设备显示器信息 与 配置(横竖屏、语言等) 创建Resources
Resources skinResource = new Resources(assetManager, appResource.getDisplayMetrics
(), appResource.getConfiguration());
4.使用PackageManager,根据皮肤包路径获取皮肤包包名
//获取外部Apk(皮肤包) 包名
PackageManager mPm = mContext.getPackageManager();
PackageInfo info = mPm.getPackageArchiveInfo(skinPath, PackageManager
.GET_ACTIVITIES);
String packageName = info.packageName;
5.注册ActivityLifeCycle,监测activity oncreate回调,配置自定义的layoutInflater对象,自定义layoutinflater对象接管View 的创建过程,在创建View时统计需要替换属性的view
//记录换肤需要操作的View与属性信息
private List<SkinView> mSkinViews = new ArrayList<>();
//记录下一个VIEW身上哪几个属性需要换肤textColor/src
public void look(View view, AttributeSet attrs) {
List<SkinPair> mSkinPars = new ArrayList<>();
for (int i = 0; i < attrs.getAttributeCount(); i++) {
//获得属性名 textColor/background
String attributeName = attrs.getAttributeName(i);
if (mAttributes.contains(attributeName)) {
// #
// ?
// @
String attributeValue = attrs.getAttributeValue(i);
// 比如color 以#开头表示写死的颜色 不可用于换肤
if (attributeValue.startsWith("#")) {
continue;
}
int resId;
// 以 ?开头的表示使用 属性
if (attributeValue.startsWith("?")) {
int attrId = Integer.parseInt(attributeValue.substring(1));
resId = SkinThemeUtils.getResId(view.getContext(), new int[]{ attrId})[0];
} else {
// 正常以 @ 开头
resId = Integer.parseInt(attributeValue.substring(1));
}
SkinPair skinPair = new SkinPair(attributeName, resId);
mSkinPars.add(skinPair);
}
}
if (!mSkinPars.isEmpty() || view instanceof SkinViewSupport) {
SkinView skinView = new SkinView(view, mSkinPars);
// 如果选择过皮肤 ,调用 一次 applySkin 加载皮肤的资源
skinView.applySkin();
mSkinViews.add(skinView);
}
}
6.触发换肤动作,使用resource对象获取皮肤包属性值,设置到目标view
List<SkinPair> skinPairs;
public void applySkin() {
for (SkinPair pair : skinPairs) {
Drawable left = null, top = null, right = null, bottom = null;
switch (pair.attributeName) {
case "background":
Object background = SkinResource.getInstance().getBackground(pair
.resId);
if (background instanceof Integer) {
view.setBackgroundColor((Integer) background);
} else {
ViewCompat.setBackground(view, (Drawable) background);
}
Log.e(TAG, "applySkin: background==" + background);
break;
case "textColor":
ColorStateList colorStateList = SkinResource.getInstance().getColorStateList
(pair.resId);
((TextView) view).setTextColor(colorStateList);
Log.e(TAG, "applySkin: colorStateList==" + colorStateList);
break;
case "src":
background = SkinResource.getInstance().getBackground(pair.resId);
if (background instanceof Integer) {
((ImageView) view).setImageDrawable(new ColorDrawable((Integer) background));
} else {
((ImageView) view).setImageDrawable((Drawable) background);
}
break;
}
}
}
static class SkinPair {
//属性名
String attributeName;
//资源ID
int resId;
public SkinPair(String attributeName, int resId) {
this.attributeName = attributeName;
this.resId = resId;
}
}
7.实现功能
** 新建工程包,复制原包中的资源文件同时替换设置资源值,继续生成apk并放置到特定目录下,触发加载换肤即可**
application oncreate回调方法中初始化换肤工具类:
SkinManager.init(mContext);
触发加载换肤即可
//换肤,收包裹,皮肤包是独立的apk包,可以来自网络下载
SkinManager.getInstance()
.loadSkin("/data/data/com.gerryrun.mytestapplication/skin/app-debug.apk");
完整项目请移驾:项目链接 https://gitee.com/gerryrun/skin-manager.git
还没有评论,来说两句吧...