一、为什么换肤?
- 项目UI风格的改动
每一个成熟的APP,都会在市场上存在数年,或者数十年的时间。随着时间的流逝,相关的设计语言也会随之改变。而此时,若产品要求我们改变UI样式,你看到累积多年的祖传代码,往往有种无从下手的感觉。此时修改代码,需要耗费大量的时间,也要承担不小的风险。 - 提升用户体验
随着ios与android官方推出暗黑系统,渐渐也有一部分APP随之改变。尤其是,对于阅读类APP来说,白天使用白色模式,黑天使用黑暗模式,是大量用户的实际需求。 - 用户个性化
市场上的APP数不胜数,同类型的APP也是不知凡几。为了吸引更多的用户,提高APP自增长的几率,个性化的换肤功能必然是个不错的选择。
二、换肤的基础知识
android的换肤功能,主要涉及theme、style、attr等相关属性,以及view的绘制流程、对APK的context、resouce获取等相关知识,以下是对这些核心知识点的简单讲解;
- attr
要理解attr首先要学会对它的使用,下面我们自定义一个属性。
- 自定义属性
1.定义view的属性
2.获取自定义属性值
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout);
int space = ta.getDimensionPixelSize(R.styleable.FlowLayout_space, 0);
ta.recycle();
3.使用自定义属性
在自定义属性中,我们了解到,attr是view样式中最小的单元,用于定义view中具体的属性。在任何view中,他们的背景、颜色、文字等属性,都可以通过给attr赋值而进行修改。也可以说,换肤的根本就是改变,每一个view的attr的值。
拓展知识
- attr与declare-styleable的关系:
1)attr不依赖于styleable,styleable只是为了方便attr的使用。
2)attr可以单独使用,通过obtainAttributes(AttributeSet set, int[] attrs) 获取。
3)styleable只是一个attr风格属性的集合或分组。
4)单独定义的attr,可以自己组装分组,实现更自由多变的功能。
1.在xml中声名
// 单独定义attr的属性的设置
// 单独定义attr的属性获取
// int[] customAttrs = {R.attr.custom_color};
// TypedArray a = context.obtainStyledAttributes(attrs, customAttrs);
2.在R文件中自动生成
public static final class attr {
public static final int CustomizeStyle=0x7f010004;
public static final int attr_one=0x7f010000;
public static final int attr_two=0x7f010001;
public static final int attr_three=0x7f010002;
public static final int attr_four=0x7f010003;
}
- attr属性的设置和获取:
1)在layout中设置属性:
通过命名空间(namespace)定义xml中的标签,然后,通过attr属性定义的名称,设置具体的属性值。
attr属性的获取
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomAttribute);
2)通过style设置属性:
style是一个风格样式的集合,在style.xml中定义一个style样式,在style中设置具体attr的值。在使用时,可以在xml中直接引用style,或者在代码中直接获取style;
//style 获取
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Customize, defStyle, R.style.DefaultCustomizeStyle);
3) theme中指定在当前Application或Activity中属性的默认值
theme应用于activity或application中,其作用范围是最大的。我们可以在theme中设置attr的值,然后直接应用在整个Actvity,甚至是整个App。
-
attr属性的获取:
1)从layout设置的属性集中获取attrs中的属性TypedArray ta = context.obtainStyledAttributes(attrs);
2)从系统主题中获取attrs中的属性
TypedArray ta = context.obtainStyledAttributes(attrs);
obtainStyledAttributes(int[] attrs) //
obtainStyledAttributes(int resId,int[] attrs) //从资源文件定义的style中读取属性
obtainStyledAttributes (AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)
//这是最复杂的一种情况,后面细说。
**总结**
attr、style、theme使用的方法,大同小异,主要的区别是,作用域不同。attr是应用于view或viewgroup中,style可以应用于各个
- attr属性的获取:
obtainStyledAttributes函数获取属性 - view的构造方法详解:
参考资料:深入理解Android 自定义attr Style styleable以及其应用
三、换肤如何实现?
1.静态换肤
在项目中,内置几套皮肤资源,在需要换肤的时候,直接引用相关资源。例如,常用的默认主题,黑夜白天模式。
1.1 自定义view实现
自定义一个接口,每一个需要换肤的view,都要实现这个接口。通过接口,在每次启动Activity的时候,重新加载相关的theme。通过theme主题的不同,使用setTheme方法,对内置资源进行置换,完成整体的换肤工作。
参考项目:MultipleTheme
1.2 手动绑定view与资源
ViewGroupSetter listViewSetter = new ViewGroupSetter(mNewsListView);
// 绑定ListView的Item View中的news_title视图,在换肤时修改它的text_color属性
listViewSetter.childViewTextColor(R.id.news_title, R.attr.text_color);
// 构建Colorful对象来绑定View与属性的对象关系
mColorful = new Colorful.Builder(this)
.backgroundDrawable(R.id.root_view, R.attr.root_view_bg)
// 设置view的背景图片
.backgroundColor(R.id.change_btn, R.attr.btn_bg)
// 设置背景色
.textColor(R.id.textview, R.attr.text_color)
.setter(listViewSetter) // 手动设置setter
.create(); // 设置文本颜色
需要手动更严样式
Colorful
参考资料
Android 换肤原理分析和总结
换肤技术总结
android view的绘制
Attr、Style和Theme详解
深入理解Android 自定义attr Style styleable以及其应用
开源库
MultipleTheme
Android-Skin-Loader
无侵入换肤SkinClient