一、引言
Android开发经常会遇到Attr、Style、Theme这三个词,对于这三个概率只知道一些基本的使用,却但多少有一些迷惑,总的说来Attr、Style、Theme都是用来表达样式风格的,只是范围不一样。这三个概念贯穿Android框架的方方面面,是Android程序设计中很重要的一环,理解它们,不但可以让你的代码变得简洁明了,还可以让的应用更加灵活。
控件的属性的设置的五种方式(优先级基本是从上到下):
- 直接在xml中直接定义
- 通过Style来引用外部样式
- 在对应的主题中定义外部Style引用(控件的第三个参数defStyleAttr如:textViewStyle,buttonStyle,preferenceStyle等等)
- 在对应的默认style定义(也就是控件的第四个参数defStyleRes,一般都为0,也就是没有)二
- 在对应的主题直接定义
二、定义
关于这三个概念的定义:
- Attr:属性,风格样式的最小单元
- Style:风格,它是一系列Attr的集合用以定义一个View的样式,比如height、width、padding等
- Theme:主题,它与Style作用一样,不同于Style作用于个一个单独View,而它是作用于Activity上或是整个应用
三、Attr使用
平时开发中,只有在自定义View时才会定义Attr;在values目录下创建一个attrs.xml文件,在元素里面首先申明一个自己的表示一个属性组,再在里面加上属性就行。format表示了Attr的类型,可取的值有以下类型:
- color:颜色值,如#000000
- reference:引用某一资源ID。如@drawable/xxx
- boolean:布尔值,true或false
- dimension:尺寸值,可以为wrap_content、match_parent或是具体大小(xx dp)
- float:浮点型
- fraction:百分数
- integer:整型
- string:字符串类型
- enum:枚举类型,各个取值互斥
- flag:标记位,各个取值可用“|”连接
reference用在一些可以设置引用值的情况,比如@drawable/myImage、@color/myColor等。当然format也可以进行或运算,一般我们定义color类型的属性时,也一般会把format写成format=”reference|color”,这样我们不但可以设置颜色值,如#FFFFFF,还可以使用我们自己定义的demo图片,如@drawable/demo_pic。
<declare-styleable name="SwitchView">
<attr name="hasShadow" format="boolean"/>
<attr name="primaryColor" format="color"/>
<attr name="primaryColorDark" format="color"/>
<attr name="isOpened" format="boolean"/>
</declare-styleable>
format即使用错,只要你自定义的View中获取对应类型值也是可以的,只是在布局中写代码时,IDE就不会根据你定义的format给出相应的提示了,所以最好在自定义View时还是仔细斟酌下类型。
一种常见的在自定义View类中获取Attr的代码是这样的:
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SwitchView);
colorPrimary = a.getColor(R.styleable.SwitchView_primaryColor, DEFAULT_COLOR_PRIMARY);
colorPrimaryDark = a.getColor(R.styleable.SwitchView_primaryColorDark, DEFAULT_COLOR_PRIMARY_DARK);
hasShadow = a.getBoolean(R.styleable.SwitchView_hasShadow, true);
isOpened = a.getBoolean(R.styleable.SwitchView_isOpened, false);
state = isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF;
lastState = state;
a.recycle();
四、Style使用
Style使用需要先配置参数,在values/styles.xml的 <resources>标签内增加如下内容:
<style name="LoadSeekBar" parent="@android:style/Widget.SeekBar">
<item name="android:progressDrawable">@drawable/bg_load_seekbar</item>
<item name="android:thumb">@null</item>
<item name="android:minHeight">2dp</item>
<item name="android:maxHeight">2dp</item>
</style>
<style name="nameStyle">
<item name="android:textColor">#000</item>
<item name="android:textSize">18dp</item>
</style>
如此一来,我们便定义了名为LoadSeekBar、nameStyle的Style,接下来看看如何使用它。
<ProgressBar
android:id="@+id/pb_update"
style="@style/LoadSeekBar"
android:layout_width="match_parent"
android:layout_height="5dp"
android:gravity="center"
android:progress="0" />
mfileName.setTextAppearance(mContext, R.style.nameStyle);
五、Theme使用
自定义Theme的方法与自定义Style相同,Theme与Style使用同一个元素标签 <style>区别在于所包含的属性不同,并且使用的地方也不一样。Theme需要设置到AndroidManifest.xml的 <application>或者 <activity> 标签下,设置后,被设置的Activity或整个应用下所有的View都可以使用该 <style> 里面的属性了。
<style name="StartAppTheme" parent="AppTheme">
<item name="android:windowBackground">@drawable/ic_bg_splash</item>
</style>
有一点需要注意的是,若想把自定义的Theme设置给Activity或Application,需要让的自定义Theme继承自一个系统Theme,否则会抛出IllegalStateException异常。
<activity
android:name=".activity.SplashActivity"
android:screenOrientation="portrait"
android:theme="@style/StartAppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
一个 Theme 实际上就是一个 Style,唯一的不同是他们在哪里被使用:在 Android Manifest 中为 APP 或者 activity 设置 Theme;在布局文件中为 widget 设置 Style。
六、总结
随着学习的深入,越发觉得这三块内容真是Android框架的一大神器,有时不用改动代码,只要换一个theme,应用马上焕发青春。而且也尝试用所学内容去写自己的Theme,不但可以让自己的布局文件更加清晰明了,而且还让自己的代码具有更高的扩展性,真是好处多多。
Q&A
如果想继承某个主题并修改某些属性,如何知道有哪些属性可以修改
A: 从源文件中找,如themes.xml
如何知道内置了哪些style
A: 源文件styles.xml, 或官方文档 R.style
如何知道一个View有哪些属性可用
A: 源文件attrs.xml中搜索view名称,或参考该View的官方文档
查看某主题的外观效果
A: 可以Theme Editor中查看