/Android-skin-support

Android-skin-support is an easy dynamic skin framework to use for Android, Only one line of code to integrate it. Android 换肤框架, 极低的学习成本, 极好的用户体验. "一行"代码就可以实现换肤, 你值得拥有!!!

Primary LanguageJavaMIT LicenseMIT

Android-skin-support

介绍

Android-skin-support: 一款 Android 换肤框架, 极低的学习成本, 极好的用户体验.

只需要一行代码, 就可以实现换肤, 你值得拥有!!!

SkinCompatManager.withoutActivity(this).loadSkin();

就这么简单, 你的APK已经拥有了强大的换肤功能, 当然现在是拥有了换肤功能, 别忘了制作皮肤包.

功能

  • 支持布局中用到的资源换肤。
  • 支持代码中设置的资源换肤。
  • 默认支持大部分基础控件,Material Design换肤。
  • 支持多种加载策略(应用内/插件式/自定义sdcard路径)。
  • 资源加载优先级: 加载策略中的资源-应用资源。
  • 支持定制化,选择需要的模块加载。
  • 支持矢量图(vector/svg)换肤。
  • 支持AndroidX

目录结构

demo // 换肤demo 集合

skin-sample // demo app

skin-night // 夜间模式皮肤工程

androidx // Android 原生控件

skin-base // 换肤框架

skin-appcompat // 换肤框架, 基础控件支持

skin-cardview // 换肤框架, CardView 支持

skin-material // 换肤框架, Material Design 支持

skin-constraintlayout // 换肤框架, ConstraintLayout 支持

third-part // 第三方控件换肤支持

circleimageview // hdodenhof/CircleImageView支持

用法

最新版本选择, 请查看更新日志

导入:

AndroidX support:

如果项目中使用了AndroidX, 添加以下依赖

implementation 'ui.skin:skin-base:0.0.1'               // skin-base
implementation 'ui.skin:skin-appcompat:0.0.1'          // skin-appcompat 基础控件支持
implementation 'ui.skin:skin-material:0.0.1'           // skin-material MaterialDesign 控件支持[可选]
implementation 'ui.skin:skin-cardview:0.0.1'           // skin-cardview CardView 控件支持[可选]
implementation 'ui.skin:skin-constraintlayout:0.0.1'   // skin-constraintlayout ConstraintLayout 控件支持[可选]

在Application的onCreate中初始化

@Override
public void onCreate() {
    super.onCreate();
    SkinCompatManager.withoutActivity(this)
            .addInflater(new SkinAppCompatViewInflater())           // 基础控件换肤初始化
            .addInflater(new SkinMaterialViewInflater())            // MaterialDesign 控件换肤初始化[可选]
            .addInflater(new SkinConstraintViewInflater())          // ConstraintLayout 控件换肤初始化[可选]
            .addInflater(new SkinCardViewInflater())                // CardView 控件换肤初始化[可选]
            .setSkinWindowBackgroundEnable(false)                   // 关闭windowBackground换肤,默认打开[可选]
            .loadSkin();
}

如果项目中使用的Activity继承自AppCompatActivity,需要重载getDelegate()方法

@NonNull
@Override
public AppCompatDelegate getDelegate() {
    return SkinAppCompatDelegateImpl.get(this, this);
}

使用:

皮肤开关

如果项目中有特殊需求。例如, 股票控件: 控件颜色始终为红色或绿色, 不需要随着模式切换而换肤

那么可以使用类似的方法, 直接设置drawable

setBackgroundDrawable(redDrawable) // 不支持换肤
background="#ce3d3a"

而不是使用R.drawable.red

setBackgroundResource(R.drawable.red)
background="@drawable/red"

加载插件皮肤库

// 指定皮肤插件
SkinCompatManager.getInstance().loadSkin("new.skin"[, SkinLoaderListener], int strategy);

// 恢复应用默认皮肤
SkinCompatManager.getInstance().restoreDefaultTheme();

自定义View换肤

要点:

  1. 实现SkinCompatSupportable接口

  2. applySkin方法中实现换肤操作

  3. 在构造方法中解析出需要换肤的resId

应用内换肤:

应用内换肤,皮肤名为: night; 新增需要换肤的资源添加后缀或者前缀。

需要换肤的资源为R.color.windowBackgroundColor, 添加对应资源R.color.windowBackgroundColor_night。

加载应用内皮肤:

SkinCompatManager.getInstance().loadSkin("night", SkinCompatManager.SKIN_LOADER_STRATEGY_BUILD_IN); // 后缀加载

推荐将应用内换肤相关的皮肤资源放到单独的目录中

eg: res-night

注: 如果使用这种方式来增加换肤资源,记得在build.gradle 中配置一下这个资源目录 sourceSets {main {res.srcDirs = ['src/main/res', 'src/main/res-night']}}

插件式换肤:

新建Android application工程

皮肤工程包名不能和宿主应用包名相同.

例如:

宿主包名: com.skin.demo
夜间模式: com.skin.demo.night

将需要换肤的资源放到res目录下(同名资源)

例如 APK中窗口背景颜色为

colors.xml

<color name="background">#ffffff</color>

那么夜间模式你可以在skin-night工程中设置

colors.xml

<color name="background">#000000</color>

打包生成apk, 即为皮肤包

将打包生成的apk文件, 重命名为'xxx.skin', 防止apk结尾的文件造成混淆.

加载皮肤插件

加载插件式皮肤, 将皮肤包放到assets/skins目录下

SkinCompatManager.getInstance().loadSkin("night.skin", SkinCompatManager.SKIN_LOADER_STRATEGY_ASSETS);

自定义加载策略:

自定义sdcard路径

继承自SkinSDCardLoader,通过getSkinPath方法指定皮肤加载路径,通过getType方法指定加载器type。

public class CustomSDCardLoader extends SkinSDCardLoader {
    public static final int SKIN_LOADER_STRATEGY_SDCARD = Integer.MAX_VALUE;

    @Override
    protected String getSkinPath(Context context, String skinName) {
        return new File(SkinFileUtils.getSkinDir(context), skinName).getAbsolutePath();
    }

    @Override
    public int getType() {
        return SKIN_LOADER_STRATEGY_SDCARD;
    }
}

注: 自定义加载器type 值最好从整数最大值开始递减,框架的type值从小数开始递增,以免将来框架升级造成type 值冲突

在Application中,添加自定义加载策略:

SkinCompatManager.withoutActivity(this)
        .addStrategy(new CustomSDCardLoader());          // 自定义加载策略,指定SDCard路径

注: 自定义加载器必须在Application中注册,皮肤切换后,重启应用需要根据当前策略加载皮肤

使用自定义加载器加载皮肤:

SkinCompatManager.getInstance().loadSkin("night.skin", null, CustomSDCardLoader.SKIN_LOADER_STRATEGY_SDCARD);

资源加载优先级: 加载策略中的资源-应用资源。

获取当前使用皮肤

SkinPreference

缺点

  • 同一个LayoutInflater只能设置一次Factory,容易和同类库产生冲突