借助 Android 上的样式和主题,您可以将应用设计的细节与界面结构和行为分开,这与网页设计中的样式表类似。
样式是一个属性集合,用于指定单个 View 的外观。样式可以指定某些属性,例如字体颜色、字号、背景颜色等。
主题是应用于整个应用、activity 或视图层次结构,而非仅仅应用于单个视图的属性集合。应用主题时,应用或 activity 中的每个视图都会应用其支持的主题属性。主题还可以将样式应用于非视图元素,例如状态栏和窗口背景。
样式和主题在 res/values/ 中的样式资源文件中声明,该文件通常命名为 styles.xml。
图 1. 应用于同一 activity 的两个主题:Theme.AppCompat(左)和 Theme.AppCompat.Light(右)。
主题与样式
主题和样式有很多相似之处,但它们的用途不同。主题和样式具有相同的基本结构,即一个将属性映射到资源的键值对。
样式用于为特定类型的视图指定属性。例如,一种样式可能会指定按钮的属性。您在样式中指定的每个属性都是您可以在布局文件中设置的属性。将所有属性提取到样式中,可让您轻松地在多个 widget 中使用和维护这些属性。
主题定义了一组可由样式、布局、微件等引用的命名资源。主题会为 Android 资源分配语义名称,例如 colorPrimary。
样式和主题背景应当配合使用。例如,您可能有一个样式指定按钮的一部分为 colorPrimary,另一部分为 colorSecondary。这些颜色的实际定义在主题中提供。当设备进入夜间模式时,您的应用可以从“浅色”主题切换到“深色”主题,从而更改所有这些资源名称的值。您无需更改样式,因为样式使用的是语义名称,而不是特定的颜色定义。
如需详细了解主题和样式如何协同工作,请参阅博文 Android 样式设置:主题与样式。
创建并应用样式
如需创建新样式,请打开项目的 res/values/styles.xml 文件。对于要创建的每种样式,请按以下步骤操作:
- 使用唯一标识样式的名称添加
<style>元素。 - 为您要定义的每个样式属性添加一个
<item>元素。每个 item 中的name会指定您原本会在布局中作为 XML 属性来使用的属性。<item>元素中的值是该属性的值。
例如,假设您定义了以下样式:
<?xml version="1.0" encoding="utf-8"?> <resources> <style name="GreenText" parent="TextAppearance.AppCompat"> <item name="android:textColor">#00FF00</item> </style> </resources>
您可以将该样式应用到视图,如下所示:
<TextView style="@style/GreenText" ... />
如果视图接受样式中指定的每个属性,系统会将这些属性应用于该视图。视图会忽略它不接受的任何属性。
不过,您通常不会将样式应用于单个视图,而是将样式作为主题背景应用于整个应用、activity 或视图集合,如本指南的其他部分所述。
扩展和自定义样式
创建自己的样式时,请务必从框架或支持库中扩展现有样式,以便与平台界面样式保持兼容。如需扩展样式,请使用 parent 属性指定您要扩展的样式。然后,您可以替换继承的样式属性并添加新属性。
例如,您可以继承 Android 平台的默认文本外观,并按如下方式对其进行修改:
<style name="GreenText" parent="@android:style/TextAppearance"> <item name="android:textColor">#00FF00</item> </style>
不过,请始终从 Android 支持库继承核心应用样式。支持库中的样式通过针对每个版本中可用的界面属性优化每个样式来提供兼容性。支持库样式的名称通常与平台中的样式类似,但包含 AppCompat。
如需从库或您自己的项目中继承样式,请声明父级样式名称,不包含上例中所示的 @android:style/ 部分。例如,以下示例从支持库继承文本外观样式:
<style name="GreenText" parent="TextAppearance.AppCompat"> <item name="android:textColor">#00FF00</item> </style>
您还可以通过使用点表示法扩展样式的名称(而不是使用 parent 属性)来继承样式(平台中的样式除外)。也就是说,在样式名称前面加上要继承的样式的名称,并用英文句点分隔。通常,您只有在扩展自己的样式(而非其他库中的样式)时才会这样做。例如,以下样式会继承上例中 GreenText 的所有样式,然后增大文本大小:
<style name="GreenText.Large"> <item name="android:textSize">22dp</item> </style>
您可以根据需要多次继续继承此类样式,只需链接更多名称即可。
如需了解您可以使用 <item> 标记声明哪些属性,请参阅各种类引用中的“XML 属性”表。所有视图都支持来自 View 基类的 XML 属性,并且许多视图会添加自己的特殊属性。例如,TextView XML 属性包含 android:inputType 属性,您可以将其应用于接收输入的文本视图,例如 EditText widget。
将样式作为主题背景来应用
您可以像创建样式一样创建主题背景。区别在于应用方式:您不是在视图上使用 style 属性应用样式,而是在 AndroidManifest.xml 文件中的 <application> 标记或 <activity> 标记上使用 android:theme 属性应用主题。
例如,以下代码展示了如何将 Android 支持库的 Material Design“深色”主题应用于整个应用:
<manifest ... > <application android:theme="@style/Theme.AppCompat" ... > </application> </manifest>
下面的代码演示了如何将“浅色”主题应用到一个 activity:
<manifest ... > <application ... > <activity android:theme="@style/Theme.AppCompat.Light" ... > </activity> </application> </manifest>
应用或 activity 中的每个视图都会应用给定主题背景中定义的样式(如果该视图支持这些样式)。如果视图仅支持样式中声明的部分属性,则它仅应用这些属性,而忽略不支持的属性。
从 Android 5.0(API 级别 21)和 Android 支持库 v22.1 开始,您还可以在布局文件中为视图指定 android:theme 属性。这会修改该视图和任何子视图的主题,这对于更改界面特定部分的主题调色板非常有用。
前面的示例展示了如何应用 Android 支持库提供的主题(例如 Theme.AppCompat)。不过,您通常需要自定义主题,使其契合应用的品牌。实现此目的的最佳方式是,从支持库扩展这些样式并替换部分属性,如以下部分所述。
样式层次结构
Android 提供了多种方法来在整个 Android 应用中设置属性。例如,您可以直接在布局中设置属性、将样式应用于视图、将主题应用于布局,甚至以编程方式设置属性。
在选择如何为应用设置样式时,需考虑 Android 的样式层次结构。一般而言,应尽可能使用主题和样式,以保持一致性。如果您在多个位置指定了相同的属性,则以下列表将决定最终应用哪些属性。该列表按优先级从高到低的顺序排列。
- 使用文本 span 将字符级或段落级样式应用于
TextView派生类。 - 以编程方式应用属性。
- 直接将各个属性应用于视图。
- 将样式应用于视图。
- 默认样式。
- 将主题应用于一组视图、一个 activity 或整个应用。
- 应用某些特定于视图的样式,例如在
TextView上设置TextAppearance。
图 2. span 中的样式会覆盖 textAppearance 中的样式。
TextAppearance
样式的一个局限性在于,您只能对 View 应用一种样式。不过,在 TextView 中,您还可以指定一个功能类似于样式的 TextAppearance 属性,如以下示例所示:
<TextView ... android:textAppearance="@android:style/TextAppearance.Material.Headline" android:text="This text is styled via textAppearance!" />
TextAppearance 可让您定义文本专用样式,同时让 View 的样式可用于其他用途。但请注意,如果您直接在 View 上或在样式中定义任何文本属性,这些值会覆盖 TextAppearance 值。
TextAppearance 支持 TextView 提供的一部分样式属性。如需查看完整的属性列表,请参阅 TextAppearance。
未包含的一些常见 TextView 属性为 lineHeight[Multiplier|Extra]、lines、breakStrategy 和 hyphenationFrequency。TextAppearance 在字符级(而非段落级)运行,因此不支持影响整个布局的属性。
自定义默认主题背景
当您使用 Android Studio 创建项目时,它会默认将 Material Design 主题应用于您的应用,如项目的 styles.xml 文件中所定义。此 AppTheme 样式扩展了支持库中的主题,并包含对关键界面元素(例如应用栏和悬浮操作按钮,如果使用的话)所用颜色属性的替换。因此,您可以通过更新提供的颜色,快速自定义应用的颜色设计。
例如,您的 styles.xml 文件如下所示:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style>
样式值实际上是对在项目的 res/values/colors.xml 文件中定义的其他颜色资源的引用。您可以通过修改该文件来更改颜色。
请参阅 Material Design 颜色概览,了解如何通过动态配色和其他自定义颜色来提升用户体验。
了解颜色后,请更新 res/values/colors.xml 中的值:
<?xml version="1.0" encoding="utf-8"?> <resources> <!-- Color for the app bar and other primary UI elements. --> <color name="colorPrimary">#3F51B5</color> <!-- A darker variant of the primary color, used for the status bar (on Android 5.0+) and contextual app bars. --> <color name="colorPrimaryDark">#303F9F</color> <!-- a secondary color for controls like checkboxes and text fields. --> <color name="colorAccent">#FF4081</color> </resources>
然后,您可以根据需要替换任何其他样式。例如,您可以按如下方式更改 activity 背景颜色:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> ... <item name="android:windowBackground">@color/activityBackground</item> </style>
如需查看可以在主题中使用的属性的列表,请参阅位于 R.styleable.Theme 的属性表。为布局中的视图添加样式时,您还可以通过查看视图类参考文档中的“XML 属性”表来查找属性。例如,所有视图都支持来自基类 View 的 XML 属性。
大多数属性都应用于特定类型的视图,有些则应用于所有视图。不过,R.styleable.Theme 中列出的某些主题属性会应用于 activity 窗口,而不是布局中的视图。例如,windowBackground 会更改窗口背景,而 windowEnterTransition 会定义在 activity 启动时使用的过渡动画。如需了解详情,请参阅使用动画启动 activity。
Android 支持库还提供了其他属性,可用于自定义从 Theme.AppCompat 扩展的主题,例如上述示例中所示的 colorPrimary 属性。最好在库的 attrs.xml 文件中查看这些内容。
支持库中还提供了其他不同的主题,您可能希望扩展这些主题,而不是上例中所示的主题。如需查看可用主题,最好查看库的 themes.xml 文件。
添加特定于版本的样式
如果新版 Android 添加了您想使用的主题属性,您可以将其添加到您的主题中,同时仍与旧版本兼容。您只需将另一个 styles.xml 文件保存在包含资源版本限定符的 values 目录中:
res/values/styles.xml # themes for all versions res/values-v21/styles.xml # themes for API level 21+ only
由于 values/styles.xml 文件中的样式适用于所有版本,因此 values-v21/styles.xml 中的主题可以继承这些样式。这意味着,您可以从“基本”主题开始,然后在特定于版本的样式中扩展该主题,从而避免重复样式。
例如,如需为 Android 5.0(API 级别 21)及更高版本声明窗口转换,您需要使用新属性。因此,res/values/styles.xml 中的基本主题可能如下所示:
<resources> <!-- Base set of styles that apply to all versions. --> <style name="BaseAppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="colorPrimary">@color/primaryColor</item> <item name="colorPrimaryDark">@color/primaryTextColor</item> <item name="colorAccent">@color/secondaryColor</item> </style> <!-- Declare the theme name that's actually applied in the manifest file. --> <style name="AppTheme" parent="BaseAppTheme" /> </resources>
然后,在 res/values-v21/styles.xml 中添加特定于版本的样式,如下所示:
<resources> <!-- extend the base theme to add styles available only with API level 21+ --> <style name="AppTheme" parent="BaseAppTheme"> <item name="android:windowActivityTransitions">true</item> <item name="android:windowEnterTransition">@android:transition/slide_right</item> <item name="android:windowExitTransition">@android:transition/slide_left</item> </style> </resources>
现在,您可以在清单文件中应用 AppTheme,系统会选择适用于每个系统版本的样式。
如需详细了解如何针对不同设备使用备用资源,请参阅提供备用资源。
自定义微件样式
框架和支持库中的每个 widget 都有默认样式。例如,当您使用支持库中的主题设置应用样式时,系统会使用 Widget.AppCompat.Button 样式设置 Button 实例的样式。如果您想为按钮应用其他 widget 样式,可以使用布局文件中的 style 属性来实现。例如,以下代码会应用库的无边框按钮样式:
<Button style="@style/Widget.AppCompat.Button.Borderless" ... />
如果您想将此样式应用于所有按钮,可以在主题的 buttonStyle 中声明该样式,如下所示:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="buttonStyle">@style/Widget.AppCompat.Button.Borderless</item> ... </style>
您还可以扩展 widget 样式,就像扩展任何其他样式一样,然后在布局或主题中应用自定义 widget 样式。
其他资源
如需详细了解主题和样式,请参阅下面列出的其他资源: