样式和主题背景

试用 Compose 方式
Jetpack Compose 是推荐在 Android 设备上使用的界面工具包。了解如何在 Compose 中使用主题设置。

借助 Android 上的样式和主题,您可以将应用设计的细节与界面结构和行为分离开来,类似于网页设计中的样式表。

样式是用于指定单个 View 外观的属性集合。样式可以指定字体颜色、字号、背景颜色等属性。

主题是应用于整个应用、activity 或视图层次结构(而不仅仅是单个视图)的属性集合。当您应用主题时,应用或 activity 中的每个视图都会应用其支持的每个主题属性。主题还可以将样式应用于非视图元素,例如状态栏和窗口背景。

样式和主题在 res/values/ 中的样式资源文件(通常命名为 styles.xml)中声明。

图 1. 应用于同一 activity 的两个主题:Theme.AppCompat(左)和 Theme.AppCompat.Light(右)。

主题与样式

主题和样式有许多相似之处,但其用途不同。主题和样式具有相同的基本结构,即将属性映射到资源的键值对。

样式用于为特定类型的视图指定属性。例如,一种样式可以指定按钮的属性。您在样式中指定的每个属性都是您可以在布局文件中设置的属性。通过将所有属性提取为样式,您可以轻松地在多个 widget 中使用和维护这些属性。

主题背景定义可由样式、布局、widget 等引用的命名资源的集合。主题会为 Android 资源分配语义名称,例如 colorPrimary

样式和主题背景应当配合使用。例如,您可能有一个样式指定按钮的一部分为 colorPrimary,另一部分为 colorSecondary。这些颜色的实际定义在主题中提供。当设备进入夜间模式时,您的应用可以从“浅色”主题切换到“深色”主题,从而更改所有这些资源名称的值。您无需更改样式,因为样式使用的是语义名称,而不是特定的颜色定义。

如需详细了解如何搭配使用主题和样式,请参阅博文 Android 样式设置:主题与样式

创建并应用样式

如需创建新样式,请打开项目的 res/values/styles.xml 文件。对于您要创建的每种样式,请按以下步骤操作:

  1. 使用唯一标识样式的名称添加 <style> 元素。
  2. 为您要定义的每个样式属性添加一个 <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 的样式层次结构。一般来说,请尽可能使用主题背景和样式,以保持一致性。如果您在多个位置指定相同的属性,下面的列表决定了最终会应用哪些属性。该列表按优先级从高到低排序。

  1. 使用文本 span 将字符级或段落级样式应用于 TextView 派生的类。
  2. 以编程方式应用属性。
  3. 将各个属性直接应用于视图。
  4. 将样式应用于视图。
  5. 默认样式。
  6. 将主题应用于视图集合、某个 activity 或整个应用。
  7. 应用某些视图专用样式,例如在 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]linesbreakStrategyhyphenationFrequencyTextAppearance 作用于字符级别而不是段落级别,因此不支持影响整个布局的属性。

自定义默认主题背景

当您使用 Android Studio 创建项目时,它会默认按照项目的 styles.xml 文件中的定义,将 Material Design 主题应用于您的应用。此 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,系统将选择适用于每个系统版本的样式。

如需详细了解如何针对不同设备使用备用资源,请参阅提供备用资源

自定义微件样式

框架和支持库中的每个微件都有一个默认样式。例如,当您使用支持库中的主题背景为应用设置样式时,Button 的实例会使用 Widget.AppCompat.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>

您还可以扩展微件样式,就像扩展任何其他样式一样,然后在布局或主题中应用自定义微件样式。

其他资源

要详细了解主题背景和样式,请参阅下面列出的其他资源:

博文