网站模板文件怎么下载/廊坊seo排名优化
使用 Style
Android 中的View、Window等控件通常会定义一些属性来表示各自的外观、格式等信息,例如一个TextView中的字体大小、字体颜色,一个Dialog的窗口类型、窗口大小等。而Style就是设置到一个View或者Window上的一系列属性的集合。我们可以将TextView的字体样式、字体颜色、字体大小等属性定义成一个Style,所有使用这个Style的TextView将会有相同的字体样式、字体颜色、字体大小。
Style一般是以xml文件的形式保存在资源目录中的,并且是与布局资源layout文件分离开来的,这样我们就可以将一套Style与使用这套Style的控件分离开来,进行独立维护,而且还可以将同一套Style复用到多个控件上,方便移植。从这一点上看Style有点类似于网页设计中的CSS,允许开发者将设计与内容分离。
下面是layout中一个TextView的定义,其中的typeface
、textColor
、textSize
几个属性是直接定义的:
<TextView
android:layout_width="wrap_content"android:layout_height="wrap_content"android:typeface="monospace"android:textColor="#ffff00ff"android:textSize="24sp"android:text="@string/hello_world"/>
如果我们将这几个属性分离出来,定义成一个Style,就会是下面的样子:
Style:
<style name="CodeFont"><item name="android:layout_width">wrap_content</item><item name="android:layout_height">wrap_content</item><item name="android:typeface">monospace</item><item name="android:textColor">#ffff00ff</item><item name="android:textSize">24sp</item>
</style>
Layout:
<TextView
style="@style/CodeFont"android:text="@string/hello_world" />
这样CodeFont
这个Style还可以应用到其他的TextView,而且只需要修改CodeFont
,所有使用这个Style的TextView都会改变样式。
使用 Theme
Theme其实就是应用到Activity或者Application上的Style。如上面我们刚刚定义的CodeFont
,还可以按下面的方式应用到Activity或者Application上。在AndroidManifest.xml
中可以如下设置:
<application
android:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/CodeFont" ><activity
android:name=".MainActivity"android:label="@string/app_name"android:theme="@style/CodeFont" >...<activity>...
</application>
如果Theme应用到Activity上,那么这个Activity中所有的View、Window都会使用Theme中定义的属性。同样,如果Theme应用到Application上,那么这个Application中所有的Activity中的View、Window都会使用Theme中定义的属性。
经过上面的介绍我们可以知道,Style和Theme的区别就在于应用的范围不同。Style是应用到单独的一个View上的,而Theme是应用到一个Activity或者Application中的View上的。
Style、Theme的继承性
Style是可以继承的,子Style可以继承父Style定义的属性,并重写父Style的属性。
如下面代码,Style CodeFont通过parent
属性继承自系统的Style TextAppearance
,并修改了textColor
、typeface
等几个属性,而其他没有修改的属性默认会使用TextAppearance中的定义。
<style name="CodeFont" parent="@android:style/TextAppearance"><item name="android:layout_width">fill_parent</item><item name="android:layout_height">wrap_content</item><item name="android:textColor">#00FF00</item><item name="android:typeface">monospace</item>
</style>
而如果是想从自己定义的Style继承,可以不使用parent
关键字,而是把父Style名称做为子Style名称的前缀。如下面,CodeFont.Red
继承自CodeFont
,并修改了textColor
属性为#FF0000
:
<style name="CodeFont.Red"><item name="android:textColor">#FF0000</item>
</style>
使用系统Theme
Android系统资源中已经定义了很多的Style和Theme,如Android 4.0之前使用的默认Theme,Android 4.0之后引入的Holo系列Theme,Android 5.0之后引入的Material系列Theme。我们可以在自己的应用中直接使用这些系统内置的Theme或者从这些Theme继承子Theme并进行修改。
上面介绍的Theme并不是支持Android所有的版本,如Holo风格的Theme只支持Android 4.0+的版本,Material风格的Theme只支持Android 5.0+的版本,那么我们想让我们的应用能够自己根据不同的Android版本适配不同的Theme呢?看下面:
AndroidManifest.xml
<application
android:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" >...
</application>
res/values/styles.xml
<style name="AppTheme" parent="@android:style/Theme">
</style>
res/values-v14/styles.xml
<style name="AppTheme" parent="@android:style/Theme.Holo">
</style>
res/values-v21/styles.xml
<style name="AppTheme" parent="@android:style/Theme.Material">
</style>
我们先在默认的资源目录res/values/下定义了一个AppTheme
,继承自系统的默认Theme,在Android 4.0的资源目录res/values-v14/下面重新定义AppTheme
,并继承自Theme.Holo
,在Android 5.0的资源目录res/values-v21/下面重新定义AppTheme
,并继承自Theme.Material
,这样应用在Android 4.0之前的版本上运行时会使用默认Theme,在Android 4.0 ~Android 4.4版本上运行时会使用Holo主题,在Android 5.0+的版本上会使用Material主题。
定义 Style
前面了解了Styles都是在xml资源文件里定义的,那么在资源文件里定义的这些Styles最后是怎么应用到对应的View上的,而一个View的各个属性又是在哪里定义的呢?
我们先看一看Android系统资源的源码,没有源码的同学可以到http://androidxref.com/去看。
Android系统中定义的资源都是放在源码的frameworks/base/core/res目录里的,每个View属性都是定义在res/values/attrs.xml文件里的,如下面TextView
属性的定义:
frameworks/base/core/res/res/values/attrs.xml
<declare-styleable name="TextView">...<!-- Text to display. --><attr name="text" format="string" localization="suggested" /><!-- Hint text to display when the text is empty. --><attr name="hint" format="string" /><!-- Text color. --><attr name="textColor" />...
</declare-styleable>
这里为TextView
定义了一个<declare-styleable>
元素,也就是定义了一个Style。里面的每个<attr>
为TextView
定义了一个属性,如text
、hint
、textColor
等属性,format
表示该属性的格式,主要有以下几种:
格式属性 | 说明 |
---|---|
reference | 指向其他资源的引用 |
string | 字符串资源 |
integer | 整数类型的资源 |
boolean | 布尔值类型的资源 |
color | 颜色资源 |
float | 浮点型资源 |
dimension | 带有单位的数据资源,如14sp ,15dp |
fraction | 百分数资源,如20% ,30%p |
enum | 枚举型资源 |
flags | 位标记资源 |
解析Style
应用的编译过程中资源编译工具aapt会自动创建一个R.java文件,里面会为应用中所有的资源、属性定义一个ID。编译系统资源framework-res时也会生成一个R.java,里面会创建一个styleable
类来存放所有View的属性定义,如下面是上面看到的TextView
里定义的几个属性:
out/target/common/obj/APPS/framework-res_intermediates/src/android/R.java
public static final class styleable {...public static final int TextView_text = 18;public static final int TextView_hint = 19;public static final int TextView_textColor = 5;...
}
在资源类R.java里text
、hint
、textColor
几个属性被定义成了TextView_text
、TextView_hint
、TextView_textColor
等的int型变量。那么这些变量是怎么使用的呢?
我们可以看一下TextView
构造方法里的代码:
frameworks/base/core/java/android/widget/TextView.java
CharSequence text = "";
CharSequence hint = null;final Resources.Theme theme = context.getTheme();
TypedArray a = theme.obtainStyledAttributes(attrs, com.android.internal.R.styleable.TextView, defStyleAttr, defStyleRes);int n = a.getIndexCount();
for (int i = 0; i < n; i++) {int attr = a.getIndex(i);switch (attr) {...case com.android.internal.R.styleable.TextView_hint:hint = a.getText(attr);break;case com.android.internal.R.styleable.TextView_text:text = a.getText(attr);break;...}
}
a.recycle();setText(text, bufferType);
if (hint != null) setHint(hint);
- 这里先定义了text、hint两个字符串;
- 通过context.getTheme()得到一个Resources.Theme,这就是一个主题。;
- 通过theme.obtainStyledAttributes得到一个TypedArray,这是一个资源属性数组,包含这我们在Theme里定义的所有属性的值;
- 通过遍历TypedArray里的所有属性,找到TextView_hint、TextView_text属性对应的值,赋值给hint和text;
- TextView使用text、hint的值。
上面介绍的是Style和Theme的定义方法和使用原理,至于更深层次的资源解析方面的问题暂时不做讨论。
下面有一个主题切换的小Demo,有兴趣的可以看一下。
https://github.com/geyunfei/ThemeDemo