上一篇文章中我们已经拿到了App中的resId,通过下面的代码可以拿到属性名和类型:
String resName = mAppResources.getResourceEntryName(resId);
String resType = mAppResources.getResourceTypeName(resId);
而属性名和类型在皮肤包中是一样的,通过下面的代码可以拿到皮肤包中对应的id:skinId:
int skinId = mSkinResources.getIdentifier(resName,resType,mSkinPkgName);
怎么拿到皮肤包对应mSkinResources和mSkinPkgName呢?我们可以看看Resources.java类的构造函数:Resources(AssetManager assets, DisplayMetrics metrics, Configuration config),它需要3个参数,后2个参数可以直接获取到,第1个参数需要AssetManager对象,通过下面这段代码获取到mSkinResources和mSkinPkgName,其中skinPath是皮肤包的路径:
//反射创建AssetManager
AssetManager assetManager = AssetManager.class.newInstance();
//资源路径设置
Method addAssetPath = assetManager.getClass().getMethod("addAssetPath",
String.class);
addAssetPath.invoke(assetManager, skinPath);
//宿主App的 resources;
Resources appResource = mContext.getResources();
//根据当前的设备显示器信息 与 配置(横竖屏、语言等) 创建Resources
Resources skinResource = new Resources(assetManager, appResource.getDisplayMetrics(),
appResource.getConfiguration());
//获取皮肤包包名
PackageManager mPm = mContext.getPackageManager();
PackageInfo info = mPm.getPackageArchiveInfo(skinPath, PackageManager.GET_ACTIVITIES);
String packageName = info.packageName;
这样我们就拿到了mSkinResources和mSkinPkgName, 然后就可以获取到skinId了, 结合上一篇文章中获取到的view,把skinId设置给view即可达到换肤的效果。
换肤步骤总结
1.使用换肤后的资源文件编译出apk,注意资源文件要与换肤前的同名;
2.反射设置mFactorySet为false,自定义类实现LayoutInflater.Factory2接口,重写onCreateView()方法,并将view、AttributeSet、resId等属性保存起来,setFactory2()为这个自定义类,注意这一步要在setContentView()之前调用;
3.根据resId拿到换肤前的resName和resType。传入换肤apk路径,反射创建AssetManager,然后创建Resources,然后通过Resources、resName、resType以及换肤apk的包名拿到换肤后的skinId;
4.根据skinId拿到皮肤中的color和drawable对象,设置资源的属性为皮肤中的color和drawable对象。








网友评论