Android - Style 和 Theme 的那点儿事

Style and Themes

简介

Android 中,Styles 和 Themes 是很重要的一块,很大程度上影响着应用的美观程度,虽然可能在座的广大程序猿要说“好不好看得看 UI 设计啊,即便不好看我也不背锅”,但是如果不了解 Style 和 Theme,当 UI 提供给你一个漂亮到惊为天人的设计,你却无法在 Android 中将其还原,这岂不是很尴尬。。因此可以说Style 和 Theme 是 Android 必学的基础知识之一。

实际上类似于 Web 开发中的 CSS 一样,和 HTML 分离,各自负责不同的部分,Android 中也是如此,Style 和 Theme 使得我们可以将界面的细节从 UI 结构和 behavior 中分离出来,并通过继承特性,使得良好的设计具备很好的复用性,便于项目的维护。

Style 和 Theme 本质上可以说没什么区别,硬要说的话,也就是包含的属性和使用范围的区别(个人理解~)。

  • Style (样式):为单个 View (视图)指定外观的 attributes (属性)集合。样式可以指定属性,例如字体颜色、字体大小、背景颜色等等。
  • Theme (主题):是应用于整个 Application、Activity 或 View 结构的 Style,而不仅仅是单个 View。当 Style 应用于 Theme 时,Application 或 Activity 中的每个 View 都会应用其所支持的每个attributes;Theme 还可以将 Style 应用于非 View 元素,例如 Toolbar和窗口的background。

Style 和 Theme 在 res/values/ 目录下的 styles.xml 文件中声明,下面介绍如何使用。


style - 创建 & 应用

如果我们想要创建一个新的 style 或者 theme,我们需要在 res/values/styles.xml 中声明,如下:

  1. <resources> 标签下添加 <style> ,并通过 name 属性赋予其 唯一标识该样式的名称。
  2. <style> 下通过添加 <item> 元素来添加我们想要自定义的样式属性。每个 <item> 中的 name 都指定了在布局中作为 XML 属性使用的属性,元素的值是该属性的值。

比如我们创建了一个叫 MyTextStyle 的 Style,指定 textColor 颜色为大红色,textColorHint 颜色为 “某种灰色”。

<style name="MyTextStyle" parent="TextAppearance.AppCompat">
        <item name="textColor">#FF0000</item>
        <item name="textColorHint">#BEBEBE</item>
    </style>

接下来,我们只需要让 TextView 组件的 style 属性赋值为该 MyTextStyle 即可应用 style ,如下:

<TextView
    style="@style/MyTextStyle"
    ... />

需要注意的是:

  1. 如果 view 应用该 style,那么 style 中的每个属性都会应用到 view 中,除非 view 中不含有 style 中指定的某个属性。
  2. 该 view 的子 view 不会应用该 style,style 只会应用到单一 view,如果需要应用到整个 view 结构,需要使用 theme。

style - 自定义

创建样式时,为了保证兼容性,必须要继承现有的样式,我们指定 parent 属性来继承某个 style,通过复写其中的某些属性,或者添加我们需要的属性,以此来得到我们需要的 style。

在上面的例子中,我们继承了 TextAppearance.AppCompat 这个父样式,并复写了其中的两个属性。这个样式源自 Android 支持库,具备良好的兼容性。

如果你硬着头皮要继承 Android 平台提供的样式,那我也只能告诉你怎么写了:

<style name="MyTextStyle" parent="@android:style/TextAppearance">
    <item name="android:textColor">#FF0000</item>
        <item name="android:textColorHint">#BEBEBE</item>
</style>

Android 本身提供的和支持库中的样式,名称很像,通常支持库中的样式以 .AppCompat 结尾,同时支持库中的属性 <item> 不需要指定“android:”,原因嘛,很简单,毕竟这不是 Android 平台本身提供的样式,当然不需要了。

同时,我们也可以继承自己自定义的样式,方法基本同上,可以像上述显式指明 parent 属性,也可以直接指定 name父样式 name.XXX(称为 点表示法),如下:

<style name="MyTextStyle.Large">
    <item name="android:textSize">22dp</item>
</style>

需要注意:如果通过 点表示法命名,但是同时指明 parent 属性,父样式会覆盖子样式中复写的属性,也就是说 parent 属性优先级更高。


theme - 应用

创建 theme 的方式和 style 相同,区别只在于如何应用:

  • style:view 的 style 属性
  • theme:
    • <application><activity>android:theme 属性
    • Android 5.0+ 中 view 的 theme 属性

如下,我们将 theme 应用到 整个APP:

<manifest ... >
    <application android:theme="@style/Theme.AppCompat" ... >
    </application>
</manifest>

以下,我们将 theme 应用到单独一个 activity:

<manifest ... >
    <application ... >
        <activity android:theme="@style/Theme.AppCompat.Light" ... >
        </activity>
    </application>
</manifest>

如下,我们将 theme 应用到一个 view 结构中,这需要 Android 5.0 及以上。

<LinearLayout
    ...
    theme="@style/MyTextStyle"
    ... />

通过上述方式应用 theme ,整个 APP、activity 或 view 结构中的每个 view 都会应用给定主题中定义的样式。如果 view 只支持在 style 中声明的某些属性,那么它只应用那些属性,而忽略不支持的属性。


theme - 自定义

Android Studio 创建一个项目时,默认情况下,会创建一个 AppTheme style,它从支持库扩展了一个主题,style.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>

注意,样式值 实际上是对其他 color 资源的引用 references,在res/values/color.xml 文件中定义。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>
</resources>

然后你可以重写任何想要的样式。例如,更改活动背景颜色如下:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    ...
    <item name="android:windowBackground">@color/activityBackground</item>
</style>

注意:支持库中的属性名称不使用 android: 前缀。


style - 适应版本

如果一个新版本的 Android 添加了你想要使用的主题属性,你可以将它们添加到你的主题中,同时仍然可以与旧版本兼容。你所需要的只是另一种 style,保存在包含 资源版本限定符 的值目录中的xml文件。例如:

res/values/styles.xml        # themes for all versions
res/values-v21/styles.xml    # themes for API level 21+ only

values/styles.xml 中的 style 适用于所有版本,特定版本如values-v21/style.xml 中的 style 会继承它们。因此,可以在values/styles.xml 中设置一个“基础style”,并在特定于版本中扩展进行扩展,从而避免重复样式。

例如,要声明 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/style.xml 中的 style 添加版本特有的属性 ,如下所示:

<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>

现在,如果 manifest 文件中应用 AppTheme,系统将自动加载当前版本可用的样式。


style - 自定义控件

Android 中的每个控件都有默认样式,无论是Android 自身提供的,还是支持库提供的。

当使用来自支持库的 theme 来设计应用程序时,一个 Button 将使用 Widget.AppCompat.Button 。如果想在 Button 上应用不同的 style,那么需要在布局文件中指定 style 属性。例如,以下应用支持库中的 Borderless(无边界)样式:

<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>

除此之外,还可以扩展控件 style,就像扩展其他 style 一样,然后在布局或主题中应用自定义控件 style。


大概就这么多把,废话说了一堆,希望对大家有帮助~

猜你喜欢

转载自blog.csdn.net/whdalive/article/details/80514162