理解Attr,Style,Theme
2018-11-09 本文已影响4人
30cf443c3643
概念
- Attr:属性(Attribute),用于指定UI的某种风格样式,比如android:layout_width就是一种Attr;
- Style:风格,一系列Attr的集合,用于为UI指定一个“复合风格样式”;
- Theme:主题,与Style的作用一样,区别于Style的作用范围是View,而Theme的作用范围是Activity或Application
Attr
只有在自定义View的时候会用到Attr
<declare-styleable name="ViewGroup_Layout">
<attr name="layout_width" format="dimension">
<enum name="fill_parent" value="-1" />
<enum name="match_parent" value="-1" />
<enum name="wrap_content" value="-2" />
</attr>
<attr name="layout_height" format="dimension">
<enum name="fill_parent" value="-1" />
<enum name="match_parent" value="-1" />
<enum name="wrap_content" value="-2" />
</attr>
</declare-styleable>
layout_xxx属性的取值范围为三个枚举值 fill_parent,wrap_content 或是具体大小dp
Attr的类型,可取的值有以下类型:
- color:颜色值,如#000000
- reference:引用某一资源ID。如@drawable/xxx
- boolean:布尔值,true或false
- dimension:尺寸值,可以为wrap_content、match_parent或是具体大小(xx dp)
- float:浮点型
- fraction:百分数
- integer:整型
- string:字符串类型
- enum:枚举类型,各个取值互斥
- flag:标记位,各个取值可用“|”连接
获取自定义Attr
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyStyle);
String name = ta.getString(R.styleable.MyStyle_myName, "absfree");
. . .
ta.recycle()
}
而上面代码中的obtainStyledAttributes方法最终调用的是以下重载版本的方法
public final TypedArray obtainStyledAttributes (
AttributeSet set //属性集
, int[] attrs //想要获取的属性
, int defStyleAttr //表示一个指向Style的类型为reference的Attr
, int defStyleRes) //表示Style的资源ID
后两个参数都用于指定默认Style,当从attrs中找不到我们想要获取的属性时,就会使用默认Style,其中defStyleAttr的优先级高于defStyleRes
自定义Style
在res/values/styles.xml的<resources>标签内增加如下内容
<style name="MyStyle">
<item name="myName">absfree</item>
<item name="myWeight">66</item>
<item name="myPhoto">@drawable/absfree</item>
</style>
在MyView类中,我们便可以通过Theme的obtainStyledAttributes获取到自定义Style的值。比如以下代码可以后去到MyStyle中的myName的值。
final Resources.Theme theme = context.getTheme();
TypedArray ta = theme.obtainStyledAttributes(attrs, R.styleable.MyStyle,
defStyleAttr, defStyleRes);
String name = ta.getString(R.styleable.MyStyle_myName);
ta.recycle();
使用Theme
自定义Theme的方法与自定义Style相同,也使用<style>标签。
使用只需要在AndroidManifest.xml文件的<Application>标签或是<Activity>标签中指定一个android:theme属性
注意:若想把我们自定义的Theme设置给Activity或Application,需要让我们的自定义Theme继承自一个系统Theme,否则会抛出IllegalStateException异常
另外:Style的优先级要高于Theme,如此一来我们可以先定义整个应用的整体风格样式,然后可以根据需要对局部风格样式做出个性化修改。
获取Theme中的Attr
使用?表示从Theme中查找引用的资源名,这个google叫预定义样式,用在多主题时的场景,属性值会随着主题而改变。
在xml文件中获取Theme中Attr的语法如下
?[<package_name>:][<resource_type>/]<resource_name>
若是本应用中的Attr,则可以省去<package_name>。
比如,我们向把TextView的text指定为MyStyle中的myColor,只需按如下设置:
<TextView
. . .
android:textColor="?attr/myColor"/>
实战-如何管理用attr属性
- 建立
attr_base.xml
,里面放一些app公用的属性,如下声明attr的名称类型。
<attr name="config_color_pressed" format="color"/>
- 建立App主题
theme.xml
。同时在theme里面具体指定config_color_pressed的
<style name="AppRootTheme" parent="android:Theme.Holo.Light"/>
<style name="AppBaseTheme" parent="AppRootTheme">
<item name="config_color_pressed">@color/config_color_pressed</item>
...
</style >
- 建立
attr.xml
文件 里面放自定义View需要的属性,这个时候可以如下引用attr属性,其他地方也可以这样使用
<declare-styleable name="GroupListView">
<item name="config_color_pressed">?attr/config_color_pressed</item>
</declare-styleable>
这样来达到app样式统一。获取attr属性的时候 可以通过下面的方法
public static float getAttrFloatValue(Context context, int attrRes){
TypedValue typedValue = new TypedValue();
context.getTheme().resolveAttribute(attrRes, typedValue, true);
return typedValue.getFloat();
}
public static int getAttrColor(Context context, int attrRes){
TypedValue typedValue = new TypedValue();
context.getTheme().resolveAttribute(attrRes, typedValue, true);
return typedValue.data;
}
public static ColorStateList getAttrColorStateList(Context context, int attrRes){
TypedValue typedValue = new TypedValue();
context.getTheme().resolveAttribute(attrRes, typedValue, true);
return ContextCompat.getColorStateList(context, typedValue.resourceId);
}
public static Drawable getAttrDrawable(Context context, int attrRes){
int[] attrs = new int[] { attrRes };
TypedArray ta = context.obtainStyledAttributes(attrs);
Drawable drawable = ta.getDrawable(0);
ta.recycle();
return drawable;
}
public static int getAttrDimen(Context context, int attrRes){
TypedValue typedValue = new TypedValue();
context.getTheme().resolveAttribute(attrRes, typedValue, true);
return TypedValue.complexToDimensionPixelSize(typedValue.data, QMUIDisplayHelper.getDisplayMetrics(context));
}
具体可以参考腾讯QMUI安卓版本的代码