Android实现换肤思路整理

整体思路总结:

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值