动态换肤在很多android应用中都有使用,用户根据自己的喜好设置皮肤主题,可以增强用户使用应用的舒适度。

Android换肤可以分为很多种,它们从使用方式,用户体验以及项目框架设计上体现了明显的差异。

接下来几篇文章分别讲解其中比较主流的换肤方式。

应用内置皮肤实现动态切换在技术上是最容易实现的,但有很多局限性,比如不能在使用过程中增减皮肤,除非升级应用,扩展性很弱;如果需要设置皮肤的位置很多,编码起来比较麻烦。主要是使用 SharedPreferences记录当前设置的皮肤序号,然后加载这套皮肤的所有资源,在每个activity中有一个setSkin()的方法设置皮肤。

博主的个人项目好记单词 中的换肤功能就是使用这个方案,感兴趣可以下载看一看,效果还不错。

实现:

  • 确定需要换肤的地方

    首先要确定应用中那些界面需要换肤,他们有什么共性?比如天天动听,一套以蓝色为基调的皮肤,所有的界面title应该是蓝色的,所有的按钮也是蓝色系列的…,这样就可以确定一套皮肤需要哪些颜色以及资源文件。

  • 确定一套皮肤需要的资源(其余皮肤按照第一套皮肤模板做)

    比如首页,四个模块,其中 本地音乐和 最近播放 的颜色是一样的,这里需要两个颜色值(正常和按下状态),歌曲下载 和 MV下载 的颜色是一样的,这里也需要两个颜色值,每个界面的标题背景色相同,然后一些按钮也需要两个颜色值;综合起来就需要7个色值,在color.xml文件中定义好它们,然后再drawable目录定义好选择器。

    (以下是Demo中的代码片段,真实项目开发中只需要按照这个步骤模板做就行)

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- 皮肤1 主色调 天蓝#4AC2E3-->
    <!-- 界面背景 -->
    <color name="pf1_activity_bg_color1">#46BAE3</color>
    <color name="pf1_activity_bg_color2">#63f3e3</color>
    <!-- item选择器 -->
    <color name="pf1_main_item_bg1">#50CEE3</color>
    <color name="pf1_main_item_bg2">#4AC2E3</color>
    <!-- 字体颜色黑色 -->
    <color name="pf1_text_color">#000000</color>               

    <!-- 皮肤2 主色调 草绿#53CAC3-->
    <!-- 界面背景 -->
    <color name="pf2_activity_bg_color1">#53CAC3</color>
    <color name="pf2_activity_bg_color2">#73FFB9</color>
    <!-- item选择器 -->
    <color name="pf2_main_item_bg1">#62E3BE</color>
    <color name="pf2_main_item_bg2">#5BD7C0</color>
    <!-- 字体颜色白色 -->
    <color name="pf2_text_color">#ffffff</color>
</resources>

  • 编写SkinUtil资源加载类
public class SkinUtil {
    private SharedPreferences sp;
    //KEY
    private final String KEY_PF = "skin";  //记录当前皮肤
    //VALUE
    public static final int VALUE_SKIN_1 = 1;   //天蓝
    public static final int VALUE_SKIN_2 = 2;   //草绿

    //当前皮肤资源ID
    public int activity_bg;
    public int item_bg;
    public int textColor;

    public SkinUtil(Context context){
        sp = context.getSharedPreferences("mySkin", Context.MODE_PRIVATE);
        loadPf();
    }
    /**
     * 设置使用那一套皮肤
     * @param witch
     */
    public void setSkin(int witch){
        sp.edit().putInt(KEY_PF, witch).commit();
        loadPf();
    }
    /**
     * 加载皮肤资源
     */
    public void loadPf(){
        //默认第一套皮肤(如果没有设置过)
        int pf_num =  sp.getInt(KEY_PF, VALUE_SKIN_1);
        switch (pf_num) {
        case VALUE_SKIN_1:
            setSkin1();
            break;
        case VALUE_SKIN_2:
            setSkin2();
            break;
        }
    }

    //加载第一套皮肤资源ID
    private void setSkin1() {
        activity_bg = R.drawable.skin1_activity_bg;
        item_bg = R.drawable.skin1_main_item_bg;
        textColor = R.color.pf1_text_color;
    }

    //加载第二套皮肤资源ID
    private void setSkin2() {
        activity_bg = R.drawable.skin2_activity_bg;
        item_bg = R.drawable.skin2_main_item_bg;
        textColor = R.color.pf2_text_color;
    }
}
  • 使用皮肤

    在Application中初始化皮肤工具类
public class MyApplication extends Application {
    public static SkinUtil skin;
    @Override
    public void onCreate() {
        super.onCreate();
        skin = new SkinUtil(getApplicationContext());
    }
}

定义BaseActivity

public abstract class BaseActivity extends Activity implements OnClickListener {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initView();
        setSkin();
    }
    protected abstract void initView();
    protected abstract void setSkin();
}

实现setSkin()方法设置皮肤

public class MainActivity extends BaseActivity{
    private LinearLayout ll_bg;
    private TextView tv_skin1, tv_skin2;
    @Override
    protected void initView() {
        setContentView(R.layout.activity_main);
        ll_bg = (LinearLayout) findViewById(R.id.ll_bg);
       ...
    }
    protected void setSkin() {
        ll_bg.setBackgroundResource(MyApplication.skin.activity_bg);
        ...
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.tv_skin1:
            //使用第一套皮肤
            MyApplication.skin.setSkin(SkinUtil.VALUE_SKIN_1);
            setSkin();
            break;
        case R.id.tv_skin2:
            //使用第二套皮肤
            MyApplication.skin.setSkin(SkinUtil.VALUE_SKIN_2);
            setSkin();
            break;
        ...
        }
    }
}

源码下载

https://github.com/openXu/SkinChange1

Android动态换肤(一、应用内置多套皮肤)的更多相关文章

  1. Android动态换肤(二、apk免安装插件方式)

    在上一篇文章Android动态换肤(一.应用内置多套皮肤)中,我们了解到,动态换肤无非就是调用view的setBackgroundResource(R.drawable.id)等方法设置控件的背景或者 ...

  2. Android动态换肤(三、安装主题apk方式)

    相比之前免安装的方式,这种方法需要用户下载并安装皮肤apk,程序写起来比免安装的要简单很多,像很多系统主题就是通过这种方式实现的. 这种方式的思路是,从所有已安装的应用程序中遍历出皮肤程序(根据特定包 ...

  3. Android应用换肤总结

    换肤,我们都很熟悉,像XP的主题,塞班的主题.看过国外的一些技术博客,就会发现国内和国外对软件的,或者说移动开发的软件的需求的不同.国外用户注重社交.邮件等功能,国内用户则重视音乐.小说.皮肤等功能, ...

  4. duilib入门之贴图描述、类html文本描述、动态换肤、Dll插件、资源打包

    转载自duilib入门文档 贴图描述: Duilib的表现力丰富很大程度上得益于贴图描述的简单强大.Duilib的贴图描述分为简单模式和复杂模式两种. 简单模式使用文件名做为贴图描述内容,在这种方式下 ...

  5. Android主题换肤实现

    本系列文章主要是对一个Material Design的APP的深度解析,主要包括以下内容 基于Material Design Support Library作为项目整体框架.对应博文:Android ...

  6. Android主题换肤 无缝切换

    2016年7月6日 更新:主题换肤库子项目地址:ThemeSkinning,让app集成换肤更加容易.欢迎star以及使用,提供改进意见. 更新日志: v1.3.0:增加一键切换切换字体(初版)v1. ...

  7. hybird之web动态换肤实现

    前言 最近在重构个hybird(原生的壳包着Web页面)的UI框架,进行到了做换肤功能的阶段,所以这里是我思考的解决的方法. 预想 目前实现换肤的功能无非就两种做法. 1.写几个皮肤文件,然后切换使用 ...

  8. CocoStudio基础教程(4)骨骼动画的动态换肤

    1.概述 游戏中人物的状态会发生改变,而这种改变通常要通过局部的变化来表现出来.比如获得一件装备后人物形象的改变,或者战斗中武器.防具的损坏等.这些变化的实现就要通过动态换肤来实现. 2.运行到程序 ...

  9. Cocos2d-x 3.0 cocostudio骨骼动画的动态换肤

    概述 游戏中人物的状态会发生改变,而这种改变通常要通过局部的变化来表现出来.比如获得一件装备后人物形象的改变,或者战斗中武器.防具的损坏等.这些变化的实现就要通过动态换肤来实现.在接下来的这个Demo ...

随机推荐

  1. [NOI 2010]航空管制

    Description 世博期间,上海的航空客运量大大超过了平时,随之而来的航空管制也频频发生.最近,小X就因为航空管制,连续两次在机场被延误超过了两小时.对此,小X表示很不满意. 在这次来烟台的路上 ...

  2. hdu 5885 FFT

    XM Reserves Time Limit: 10000/10000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others)T ...

  3. 【BZOJ1087】【SCOI2005】互不侵犯King

    Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上 左下右上右下八个方向上附近的各一个格子,共8个格子. Input 只有一行, ...

  4. bzoj 2435: [Noi2011]道路修建

    Description 在 W 星球上有 n 个国家.为了各自国家的经济发展,他们决定在各个国家 之间建设双向道路使得国家之间连通.但是每个国家的国王都很吝啬,他们只愿 意修建恰好 n – 1条双向道 ...

  5. ●BZOJ 1797 [Ahoi2009]Mincut 最小割

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1797 题解: 详细的讲解去看http://hzwer.com/3217.html首先跑一个最 ...

  6. VB6工程在Win10系统打开提示MSCOMCTL.OCX无法加载

    解决办法: 修改.vbp文件中的 00F8754DA1}#2.1#0; MSCOMCTL.OCX 改为 00F8754DA1}#2.0#0; MSCOMCTL.OCX 中间的2.1 改为 2.0

  7. ORACLE 触发器 基础

    --触发器--语法 CREATE OR REPLACE TRIGGER TRIGGER_NAME AFTER|BEFORE|INSTEAD OF [INSERT][OR UPDATE [OF COLU ...

  8. shell基本命令

    linux基本命令和shell基本命令,好多人傻傻分不清. linux基本命令积累如下: pwd:显示当前工作目录 cd:改变当前目录 ls:显示当前目录中所有目录文件和文本文件 ls -F:显示当前 ...

  9. filter和listener的生命周期

    filter(过滤器)和listener(监听器)的生命周期 老实说 生命周期要是说成作用的时间范围我会理解的更好 filter package com.javaweb.filter; import ...

  10. 读书笔记-《Maven实战》-2018/4/16

    第一章:Maven简介 1:Maven:Maven原本的单词意思为"知识的积累",谷歌翻译为"行家",而作为Apache的开源项目,Maven是一个主要服务于基 ...