Android实现换肤思路整理

水深无声 2022-10-28 10:29 269阅读 0赞

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对象

  1. mAppResources = context.getResources();

2.使用反射创建AssetManager对象

  1. //反射创建AssetManager 与 Resource
  2. AssetManager assetManager = AssetManager.class.newInstance();
  3. //资源路径设置 目录或压缩包
  4. Method addAssetPath = assetManager.getClass().getMethod("addAssetPath",
  5. String.class);
  6. addAssetPath.invoke(assetManager, skinPath);

3.根据设备的显示器信息和配置,创建Resource对象

  1. //根据当前的设备显示器信息 与 配置(横竖屏、语言等) 创建Resources
  2. Resources skinResource = new Resources(assetManager, appResource.getDisplayMetrics
  3. (), appResource.getConfiguration());

4.使用PackageManager,根据皮肤包路径获取皮肤包包名

  1. //获取外部Apk(皮肤包) 包名
  2. PackageManager mPm = mContext.getPackageManager();
  3. PackageInfo info = mPm.getPackageArchiveInfo(skinPath, PackageManager
  4. .GET_ACTIVITIES);
  5. String packageName = info.packageName;

5.注册ActivityLifeCycle,监测activity oncreate回调,配置自定义的layoutInflater对象,自定义layoutinflater对象接管View 的创建过程,在创建View时统计需要替换属性的view

  1. //记录换肤需要操作的View与属性信息
  2. private List<SkinView> mSkinViews = new ArrayList<>();
  3. //记录下一个VIEW身上哪几个属性需要换肤textColor/src
  4. public void look(View view, AttributeSet attrs) {
  5. List<SkinPair> mSkinPars = new ArrayList<>();
  6. for (int i = 0; i < attrs.getAttributeCount(); i++) {
  7. //获得属性名 textColor/background
  8. String attributeName = attrs.getAttributeName(i);
  9. if (mAttributes.contains(attributeName)) {
  10. // #
  11. // ?
  12. // @
  13. String attributeValue = attrs.getAttributeValue(i);
  14. // 比如color 以#开头表示写死的颜色 不可用于换肤
  15. if (attributeValue.startsWith("#")) {
  16. continue;
  17. }
  18. int resId;
  19. // 以 ?开头的表示使用 属性
  20. if (attributeValue.startsWith("?")) {
  21. int attrId = Integer.parseInt(attributeValue.substring(1));
  22. resId = SkinThemeUtils.getResId(view.getContext(), new int[]{ attrId})[0];
  23. } else {
  24. // 正常以 @ 开头
  25. resId = Integer.parseInt(attributeValue.substring(1));
  26. }
  27. SkinPair skinPair = new SkinPair(attributeName, resId);
  28. mSkinPars.add(skinPair);
  29. }
  30. }
  31. if (!mSkinPars.isEmpty() || view instanceof SkinViewSupport) {
  32. SkinView skinView = new SkinView(view, mSkinPars);
  33. // 如果选择过皮肤 ,调用 一次 applySkin 加载皮肤的资源
  34. skinView.applySkin();
  35. mSkinViews.add(skinView);
  36. }
  37. }

6.触发换肤动作,使用resource对象获取皮肤包属性值,设置到目标view

  1. List<SkinPair> skinPairs;
  2. public void applySkin() {
  3. for (SkinPair pair : skinPairs) {
  4. Drawable left = null, top = null, right = null, bottom = null;
  5. switch (pair.attributeName) {
  6. case "background":
  7. Object background = SkinResource.getInstance().getBackground(pair
  8. .resId);
  9. if (background instanceof Integer) {
  10. view.setBackgroundColor((Integer) background);
  11. } else {
  12. ViewCompat.setBackground(view, (Drawable) background);
  13. }
  14. Log.e(TAG, "applySkin: background==" + background);
  15. break;
  16. case "textColor":
  17. ColorStateList colorStateList = SkinResource.getInstance().getColorStateList
  18. (pair.resId);
  19. ((TextView) view).setTextColor(colorStateList);
  20. Log.e(TAG, "applySkin: colorStateList==" + colorStateList);
  21. break;
  22. case "src":
  23. background = SkinResource.getInstance().getBackground(pair.resId);
  24. if (background instanceof Integer) {
  25. ((ImageView) view).setImageDrawable(new ColorDrawable((Integer) background));
  26. } else {
  27. ((ImageView) view).setImageDrawable((Drawable) background);
  28. }
  29. break;
  30. }
  31. }
  32. }
  33. static class SkinPair {
  34. //属性名
  35. String attributeName;
  36. //资源ID
  37. int resId;
  38. public SkinPair(String attributeName, int resId) {
  39. this.attributeName = attributeName;
  40. this.resId = resId;
  41. }
  42. }

7.实现功能

** 新建工程包,复制原包中的资源文件同时替换设置资源值,继续生成apk并放置到特定目录下,触发加载换肤即可**
application oncreate回调方法中初始化换肤工具类:

  1. SkinManager.init(mContext);

触发加载换肤即可

  1. //换肤,收包裹,皮肤包是独立的apk包,可以来自网络下载
  2. SkinManager.getInstance()
  3. .loadSkin("/data/data/com.gerryrun.mytestapplication/skin/app-debug.apk");

完整项目请移驾:项目链接 https://gitee.com/gerryrun/skin-manager.git

发表评论

表情:
评论列表 (有 0 条评论,269人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Winform原理

     前两天跟着做村级节水系统,在其中遇到了换肤功能的实现。所以,想具体了解一下换肤原理。 跟踪代码,Winform换肤的实现主要是读取换肤的配置文件,然后重绘所有所有窗体