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
中声明,如下:
- 在
<resources>
标签下添加<style>
,并通过name
属性赋予其 唯一标识该样式的名称。 - 在
<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"
... />
需要注意的是:
- 如果 view 应用该 style,那么 style 中的每个属性都会应用到 view 中,除非 view 中不含有 style 中指定的某个属性。
- 该 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。
大概就这么多把,废话说了一堆,希望对大家有帮助~