插件式换肤示例代码演示

1. 思路?


对于实现插件式换肤一般来说我们有2种比较常见的方法:

思路一:

android support library23.2 支持白天和黑夜切换的(最简单,直接切换主题即可),但是这个只有白天和黑夜2套皮肤的,并且这2套皮肤是在apk里边的;

思路二:

如果需要多套皮肤来回切换,可以把皮肤从服务器下载到本地,然后直接从本地获取皮肤,这里有个问题就是,如何获取另一个apk中的资源,这里指的就是apk中的ImageView图片;

2. 效果实现


2.1>:我们写一个SkinPaign的demo,然后就只在drawable下边放一张 image_src图片,然后运行,等运行成功后,会在这个目录下边生成一个 app-debug.apk;
插件式换肤示例代码演示_第1张图片
图片.png
2.2>:然后把这个apk复制到桌面,给它重命名为 red.skin,或者其他的名称都可以,只要是 以.skin结尾的都可以,然后把这个 red.skin文件复制到 手机目录存储中,就表示我们已经把皮肤从服务器中下载到本地,这里只是做演示,就把它复制到手机存储中;
2.3>:然后我们可以通过获取另一个apk中的资源,从而获取到该资源中的图片,然后我点击一下换肤的按钮,就要把我手机上边的图片换成从手机目录中获取到的那张图片,达到 换肤的目的;

3. 效果如下图所示


点击之前:
插件式换肤示例代码演示_第2张图片
图片.png
点击之后,就替换成从手机目录中 的 red.skin文件中获取的图片:
插件式换肤示例代码演示_第3张图片
图片.png

4. 思路如下


1>:写一个demo,里边就只在drawable中放一张 图片,不做任何操作,然后会在app - build - outputs - apk下边生成一个 app-debug.apk;
2>:把这个apk复制到桌面,然后重命名为 red.skin,或者其他的以 .skin结尾的都可以;
3>:这里为了测试效果,就直接把 red.skin 文件复制到手机存储目录,表示已经从服务器下载了 皮肤到本地;
4>:然后点击 换肤的 按钮,就需要从手机目录中读取 red.skin文件,然后从中获取到 它drawable下边的那一张图片;
5>:然后用获取到的图片 替换 换肤按钮 下边的 这张图片即可;

5. 注意


这里会涉及到 ImageView的src、TextView的textColor中 资源是如何加载的源码知识,如果不是特别了解的,可以先去看下我之前的文章
ImageView的src、TextView的textColor等资源加载源码

1>:不能直接 new AssetManager()来创建对象,源码如下:
/**
     * Create a new AssetManager containing only the basic system assets.
     * Applications will not generally use this method, instead retrieving the
     * appropriate asset manager with {@link Resources#getAssets}.    Not for
     * use by applications.
     * {@hide}
     */
    public AssetManager() {
        synchronized (this) {
            if (DEBUG_REFS) {
                mNumRefs = 0;
                incRefsLocked(this.hashCode());
            }
            init(false);
            if (localLOGV) Log.v(TAG, "New asset manager: " + this);
            ensureSystemAssets();
        }
    }

发现 AssetManager上边是 hide,hide就表示只能够系统调用,我们如果想要调用只能用反射,来创建AssetManager对象;

2>:不能直接调用 asset.addAssetPath(String path),源码如下:
/**
     * Add an additional set of assets to the asset manager.  This can be
     * either a directory or ZIP file.  Not for use by applications.  Returns
     * the cookie of the added asset, or 0 on failure.
     * {@hide}
     */
    public final int addAssetPath(String path) {
         synchronized (this) {
            int res = addAssetPathNative(path, appAsLib);
            makeStringBlocks(mStringBlocks);
            return res;
        }
    }

发现这个方法也是 hide,hide就表示只能够系统调用,我们如果想要调用,就只能够通过反射,来调用 addAssetPath()方法

6. 代码如下


1>:activity_main布局文件如下:




    
2>:在MainActivity中,点击 换肤 按钮,然后利用反射从手机目录中获取 red.skin中的资源图片,然后替换本地图片即可,代码如下:
/**
 * Email: [email protected]
 * Created by JackChen 2018/4/14 20:03
 * Version 1.0
 * Params:
 * Description:  换肤测试 示例demo
*/
public class MainActivity extends BaseSkinActivity implements View.OnClickListener{

    private Button test_btn;
    private ImageView test_iv;

    @Override
    protected void initData() {

    }

    @Override
    protected void initView() {
        test_btn = (Button) findViewById(R.id.test_btn);
        test_btn.setOnClickListener(this);

        test_iv = (ImageView) findViewById(R.id.test_iv);
    }

    @Override
    protected void initTitle() {

    }

    @Override
    protected void setContentView() {
        setContentView(R.layout.activity_main);
    }

    /**
     * 1>:写一个demo,里边就只在drawable中放一张 图片,不做任何操作,然后会在app - build - outputs - apk下边生成一个 app-debug.apk;
     * 2>:把这个apk复制到桌面,然后重命名为 red.skin,或者其他的以 .skin结尾的都可以;
     * 3>:这里为了测试效果,就直接把 red.skin 文件复制到手机存储目录,表示已经从服务器下载了 皮肤到本地;
     * 4>:然后点击 换肤的 按钮,就需要从手机目录中读取 red.skin文件,然后从中获取到 它drawable下边的那一张图片;
     * 5>:然后用获取到的图片 替换 换肤按钮 下边的 这张图片;
     *
     *      以上,就达到换肤的目的;
     */
    @Override
    public void onClick(View v) {
        switch (v.getId()){

            case R.id.test_iv:
                try {
                    // 读取本地的一个 .skin里面的资源
                    Resources superRes = getResources() ;

                    // 创建AssetsManager
                    // 不能直接 new AssetManager() ;
                    // 通过反射来创建 asset对象
                    AssetManager asset = AssetManager.class.newInstance() ;
                    // 添加本地下载好的 资源皮肤,就是复制到 手机目录中的 red.skin
                    // 不能直接调用 addAssetPath()方法,只能通过反射调用 该方法
                    // 参数1:表示方法名称  参数2:表示方法里边的参数类型 如果是String path -> String.class int path -> int.class 等等

                    Method method = AssetManager.class.getDeclaredMethod("addAssetPath" , String.class) ;
                    method.setAccessible(true);  // 设置权限,防止addAssetPath()方法是私有private的

                    // 反射执行addAssetPath()方法   File.separator就和 "/" 是一样的
                    method.invoke(asset , Environment.getExternalStorageDirectory().getAbsolutePath() +
                            File.separator + "red.skin") ;
                    Resources resources = new Resources(asset , superRes.getDisplayMetrics() , superRes.getConfiguration()) ;

                    // 获取资源 id
                    // 参数1:表示图片的名称  参数2:表示类型  参数3:表示包名
                    int drawableId = resources.getIdentifier("image_src", "drawable", "cn.novate.skinpagin");
                    Drawable drawable = resources.getDrawable(drawableId) ;
                    test_iv.setImageDrawable(drawable);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                 break;

        }
    }
}

代码已上传至github:
https://github.com/shuai999/EssayJoke_day1-Two-Qi-.git

你可能感兴趣的:(插件式换肤示例代码演示)