Android-换肤ThemeSkinning使用

库源码:https://github.com/burgessjp/ThemeSkinning
参考:https://github.com/burgessjp/MaterialDesignDemo

Demo:https://github.com/huangshuyuan/SkinDemo/

1.png

2.png

3.png

1.集成步骤:

1、添加依赖 compile 'com.solid.skin:skinlibrary:1.4.3' 参考源码版本

2、让你的 Application 继承于 SkinBaseApplication

3、让你的 Activity 继承于 SkinBaseActivity,如果使用了 Fragment 则继承于 SkinBaseFragment

4、在需要换肤的根布局上添加 xmlns:skin="http://schemas.android.com/android/skin"
,然后在需要换肤的View上加上skin:enable="true"

5、新建一个项目模块(只包含有资源文件,例如本项目的 skinpackage 模块),其中包含的资源文件的 name 一定要和原项目中有换肤需求的 View 所使用的资源name一致。

6、拿到上一步生成的文件( ×××.apk ),改名为 ×××.skin,放入 assets 中的 skin 目录下( skin 目录是自己新建的)

7、调用换肤

  • 在 <code>assets/skin</code> 文件夹中的皮肤

      SkinManager.getInstance().loadSkin("Your skin file name in assets(eg:theme.skin)",
                                    new ILoaderListener() {
                                        @Override
                                        public void onStart() {
                                            Toast.makeText(getApplicationContext(), "正在切换中", Toast.LENGTH_SHORT).show();
                                        }
    
                                        @Override
                                        public void onSuccess() {
                                            Toast.makeText(getApplicationContext(), "切换成功", Toast.LENGTH_SHORT).show();
                                        }
    
                                        @Override
                                        public void onFailed() {
                                            Toast.makeText(getApplicationContext(), "切换失败", Toast.LENGTH_SHORT).show();
                                        }
                                    }
    
                            );
    
  • 皮肤来源于网络

    SkinManager.getInstance().loadSkinFromUrl(skinUrl, new ILoaderListener() {
                        @Override
                        public void onStart() {
                            Log.i("ILoaderListener", "正在切换中");
                            dialog.setContent("正在从网络下载皮肤文件");
                            dialog.show();
                        }
    
                        @Override
                        public void onSuccess() {
                            Log.i("ILoaderListener", "切换成功");
                            dialog.dismiss();
                        }
    
                        @Override
                        public void onFailed(String errMsg) {
                            Log.i("ILoaderListener", "切换失败:" + errMsg);
                            dialog.setContent("换肤失败:" + errMsg);
                        }
    
                        @Override
                        public void onProgress(int progress) {
                            Log.i("ILoaderListener", "皮肤文件下载中:" + progress);
                            dialog.setProgress(progress);
                        }
                    });
    

详细的使用,请到示例项目中查看

2.换肤属性的扩展

本开源库默认支持 textColor 和 background 的换肤。如果你还需要对其他属性进行换肤,那么就需要去自定义了。

那么如何自定义呢?看下面这个例子:

TabLayout大家应该都用过吧。它下面会有一个指示器,当我们换肤的时候也希望这个指示器的颜色也跟着更改。

  • 新建一个 TabLayoutIndicatorAttr 继承于 SkinAttr,然后重写 apply 方法。apply 方法在换肤的时候就会被调用

  • 代码的详细实现

public class TabLayoutIndicatorAttr extends SkinAttr {
    @Override
    public void apply(View view) {
        if (view instanceof TabLayout) {
            TabLayout tl = (TabLayout) view;
            if (RES_TYPE_NAME_COLOR.equals(attrValueTypeName)) {
                int color = SkinResourcesUtils.getColor(attrValueRefId);
                tl.setSelectedTabIndicatorColor(color);
            }
        }
    }
}

注:attrValueRefId:就是资源 id。SkinResourcesUtils 是用来获取皮肤包里的资源,这里设置color或者drawable一定要使用本工具类。

  • 当上面的工作完成之后,就到我们自己的 Application 的 onCreate 方法中加入<code> SkinConfig.addSupportAttr("tabLayoutIndicator", new TabLayoutIndicatorAttr());</code>

  • 最后我们就可以正常使用了,<code>dynamicAddSkinEnableView(tablayout, "tabLayoutIndicator", R.color.colorPrimaryDark);</code>

3. 关于字体切换

还是遵守本项目的约定大于配置的原则,所有的字体都放到 assets/fonts 文件夹下

如何切换字体:
<code> SkinManager.getInstance().loadFont("xx.ttf")</code>

关于切换字体需要配置的东西:
如果只是单纯的想要字体切换这个功能。只需<code>集成步骤</code>中的前三步就行了。

注:字体切换功能默认不开启,需要字体切换功能请在你的Application中加入<code>SkinConfig.setCanChangeFont(true);</code>

4. 其他一些重要的api

  1. SkinConfig.isDefaultSkin(context):判断当前皮肤是否是默认皮肤

  2. SkinManager.getInstance().restoreDefaultTheme(): 重置默认皮肤

  3. dynamicAddView:当动态创建的View也需要换肤的时候,就可以调用 dynamicAddView


5. 使用注意事项:

  1. 换肤默认只支持 android 的常用控件,对于支持库的控件和自定义控件的换肤需要动态添加(例如: <code>dynamicAddSkinEnableView(toolbar, "background", R.color.colorPrimaryDark);</code>),在布局文件中使用<code>skin:enable="true"</code>是无效的。

  2. 默认不支持状态栏颜色的更改,如果需要换肤的同时也要更改状态栏颜色,请到您的Application文件中加入<code>SkinConfig.setCanChangeStatusColor(true);</code>,状态栏的颜色值来源于<code>colorPrimaryDark</code>

  3. 本开源库使用的 Activity 是 AppCompatActivity,使用的 Fragment 是 android.support.v4.app.Fragment

  4. 有换肤需求 View 所使用的资源一定要是引用值,例如:@color/red,而不是 #ff0000

补充:支持库控件的皮肤修改

1.FloatingActionButton修改backgroundTint

需要自定义:

public class FabButtonAttr extends SkinAttr {
    @Override
    public void apply(View view) {
        if (view instanceof FloatingActionButton) {
            FloatingActionButton fb = (FloatingActionButton) view;
            if (RES_TYPE_NAME_COLOR.equals(attrValueTypeName)) {
                int color = SkinManager.getInstance().getColor(attrValueRefId);
                fb.setBackgroundTintList(ColorStateList.valueOf(color));
            } else if (RES_TYPE_NAME_DRAWABLE.equals(attrValueTypeName)) {
                //  tv.setDivider(SkinManager.getInstance().getDrawable(attrValueRefId));
            }
        }
    }
}

Application中添加:

  SkinConfig.addSupportAttr("backgroundTint",new FabButtonAttr());

使用:

   //添加改变的组件
        dynamicAddView(fab, "backgroundTint", R.color.colorPrimary);

2.NavigationView 修改点击时的item颜色

需要自定义:

public class NavigationViewAttr extends SkinAttr {
    @Override
    public void apply(View view) {
        if (view instanceof NavigationView) {
            Log.i("TabLayoutAttr", "apply");
            NavigationView nv = (NavigationView) view;
            if (RES_TYPE_NAME_COLOR.equals(attrValueTypeName)) {
                Log.i("TabLayoutAttr", "apply color");
                int color = SkinManager.getInstance().getColor(attrValueRefId);
                nv.setItemTextColor(createSelector(color));
                nv.setItemIconTintList(createSelector(color));
            } else if (RES_TYPE_NAME_DRAWABLE.equals(attrValueTypeName)) {
                Log.i("TabLayoutAttr", "apply drawable");
                //  tv.setDivider(SkinManager.getInstance().getDrawable(attrValueRefId));
            }
        }
    }

    private ColorStateList createSelector(int color) {
        int statePressed = android.R.attr.state_checked;
        int stateChecked = android.R.attr.state_checked;
        int[][] state = {{statePressed}, {-statePressed}, {stateChecked}, {-stateChecked}};
        int color1 = color;
        int color2 = Color.parseColor("#6E6E6E");
        int color3 = color;
        int color4 = Color.parseColor("#6E6E6E");
        int[] colors = {color1, color2, color3, color4};
        ColorStateList colorStateList = new ColorStateList(state, colors);
        return colorStateList;
    }
}

Application中添加:

   SkinConfig.addSupportAttr("navigationViewMenu",new NavigationViewAttr());

使用:

   //添加改变的组件
    dynamicAddView(navigationView.getHeaderView(0), "background", R.color.colorPrimary);
        dynamicAddView(navigationView, "navigationViewMenu", R.color.colorPrimary);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,522评论 25 707
  • afinalAfinal是一个android的ioc,orm框架 https://github.com/yangf...
    passiontim阅读 15,401评论 2 45
  • 1: 获取控件宽高 控件View有getHeight()和getwidth()方法可以获取宽高,但是如果直接在on...
    自由人是工程师阅读 1,767评论 0 0
  • 前情回顾:渣男日记(八) 爱情和谋杀一样,即使闭口不说,也会随着时间慢慢暴露无遗。喜欢上一个人时,你的心思就全不在...
    听任蔓草湮路阅读 910评论 0 1
  • 初中最后一个暑假的时候,我变成了插班生。原因是我的学习成绩太差,特别是英语,简直让老师怀疑人生,他勤勤恳恳、连骂带...
    半掩窗阅读 790评论 0 0