Android编程权威指南(第二版)学习笔记(二十)—— 第20章 样式与主题

本章主要讲了如何使用样式与主题(style and theme),使应用界面统一化标准化。

GitHub 地址:
完成第20章

1. 样式(Style)

1.1 样式的定义

样式是一组能应用于视图组件的属性,用于复用相同的 UI 特性

例如我们在 res/values/style.xml 中定义一个样式:

<style name="BeatBoxButton">
    <item name="android:background">@color/dark_blue</item>
    <!--其中的 color 资源在 colors.xml 中定义-->
</style>

那么使用这个样式的组件就会自动套用这个属性:

<Button
    ……
    style="@style/BeatBoxButton"
    <!--这样就能自动套用这个背景的颜色-->
    ……/>

1.2 样式的继承

样式的继承可以在原有样式的基础上添加和覆盖属性

  • 继承方式一:通过命名表示样式继承关系

    <!--用点连接表示继承关系,只能在包内使用-->
    <style name="BeatBoxButton.Strong">
        <item name="android:textStyle">bold</item>
    </style>
    
  • 继承方式二:用指定父样式的方法继承

    <!--用 parent 属性表示继承关系,可以跨库使用-->
    <style name="StrongBeatBoxButton" 
            parent="@style/BeatBoxButton">
        <item name="android:textStyle">bold</item>
    </style>
    

2. 主题(Theme)

样式能让一些属性复用,看上去节省了许多工作,在 styles.xml 公共文件中,可以为所有组件定义一套样式属性共用。然而,如果组件多了,需要逐个为所有组件添加它们要用到的样式,工作量是很大的。

这个时候主题就可以派上用场了。可以把主题看作样式的进化加强版,同样是定义一套公共主题属性,样式属性需要逐个添加,而主题属性则会自动应用于整个应用。主题属性能引用颜色这样的外部资源,也能引用其他样式。使用主题,可以简单地说:“所有按钮都使用这个样式。”再也不用找到每个按钮,告诉它们要用哪个主题了。

2.1 主题属性的更改

主题作用于某个 activity 或者整个应用,这和主题在 manifest 文件中的声明位置有关,如果在 <application> 标签中声明,则是作用于整个应用,在<activity>标签中声明,则是作用于单个 activity。

在 manifest 文件中我们看到整个应用的主题是android:theme="@style/AppTheme",按住 Command(Windows 下是 Ctrl),点击 AppTheme 就可以进入其声明的位置,可以看到以下代码:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
</style>

AppCompat 库自带三大主题:

  • Theme.AppCompat——深色主题
  • Theme.AppCompat.Light——浅色主题
  • Theme.AppCompat.Light.DarkActionBar——带深色工具栏的浅色主题
    我们把 AppTheme 的父主题修改为 Theme.AppCompat,以便于修改属性。

2.1.1 修改主题颜色

在空空的主题 style 标签中加入几个属性,如下:

<style name="AppTheme" parent="Theme.AppCompat">
    <item name="colorPrimary">@color/red</item>
    <item name="colorPrimaryDark">@color/dark_red</item>
    <item name="colorAccent">@color/gray</item>
</style>
  • colorPrimary 属性主要用来设置工具栏背景色。由于应用名称是显示在工具栏上的,colorPrimary 也可以称为应用品牌色
  • colorPrimaryDark 用于屏幕顶部的状态栏。从名字可以看出,它是深色版 colorPrimary。 注意,只有 Lollipop 以后的系统支持状态栏主题色。对于之前的系统,无论指定什么主题色,状态栏都是不变的黑底色。
  • 最后,将 colorAccent 设置为灰色的。这个主题色应该和 colorPrimary 形成反差效果,主要用于给 EditText 这样的组件着色。

2.2 主题的抽丝剥茧

完成了主题配色,我们继续来点深入的,比如可以看看可以覆盖的主题属性都有哪些。在研究诸如有哪些主题属性可用,哪些能覆盖,甚至是有某些属性究竟有什么作用等这样的问题时,几乎没有官方参考文档可以参考,所以要逐级往上查看。

例如,我想找到设置页面背景颜色的属性(随着时间的推移,主题继承关系和层次可能有变,但下面介绍的方法不会变。 想要知道该覆盖哪个属性,就沿着继承树找吧!):

第一层

也就是 AppTheme 主题,它原本是个 Android Studio 自动生成的空的主题。

为什么要生成一个空主题,而不在 manifest 中直接使用Theme.AppCompat.Light.DarkActionBar呢?这就是设计模式的事情了,对于应用本身来说,使用的主题不管父主题是谁,引用的都是 AppTheme 这个主题,相当于定义主题的时候留出了一个 AppTheme 的接口。对于协作开发来说,你不用管我内部如何实现也不用操心该怎么引用,只要使用 AppTheme 就够了。

我们继续往上找。

第二层

进入 Theme.AppCompat,可以看到其也是一个空主题:

<style name="Theme.AppCompat" parent="Base.Theme.AppCompat"/>

要进入上一层时,可以看到有好几个候选的父主题,这里我们选择 values-v21 目录下的父主题

第三层

这一层仍然是空主题

<style name="Base.Theme.AppCompat" parent="Base.V21.Theme.AppCompat"/>

那就再往上走

第四层

终于出现了很多属性

<style name="Base.V21.Theme.AppCompat" parent="Base.V7.Theme.AppCompat">
    ……
</style>

但是没有我们想要的设置背景的属性,所以要继续往上

第五层

也定义了很多属性,但是也没有需要的

<style name="Base.V7.Theme.AppCompat" parent="Platform.AppCompat">
    ……
</style>

继续往上,这里 Platform.AppCompat也有多个版本,我们选择 values-v11 下的父主题

第六层

空主题,继续往上

<style name="Platform.AppCompat" parent="Platform.V11.AppCompat"/>

第七层

终于看到了我们想要的属性:

<!--可以看到这个主题的 parent 是带有 android 命名空间的,表示其来源于 Android 系统-->
<style name="Platform.V11.AppCompat" parent="android:Theme.Holo">
        ……
        <!-- Window colors -->
        ……
        <item name="android:colorBackground">@color/background_material_dark</item>
        ……

</style>

所以,最后我们可以在 AppTheme 中覆盖这个属性,设置背景颜色:

<item name="colorBackground">@color/soothing_blue</item>

2.3 修改按钮颜色

同样的,我们再往上找,能在 android:Theme.Holo 中找到 buttonStyle 属性:

<item name="buttonStyle">@style/Widget.Holo.Button</item>

这样,我们的 BeatBoxButton 可以继承 Widget.Holo.Button 这个样式,然后在 AppTheme 中使用 buttonStyle 属性。

3. 引用主题属性

在主题中定义好属性后,可以在 XML 或代码中直接使用它们。
在 XML 中引用具体值时(如颜色值),我们使用@符号。比如 @color/gray 指向某个特定资源。
在主题中引用资源时,我们使用?符号。
比如:

<Button xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/list_item_sound_button"
    android:layout_width="match_parent"
    android:layout_height="120dp"
    android:background="?attr/colorAccent"
    tools:text="Sound name"/>

4. 挑战练习

新建 values-v21 下的 styles.xml 文件,继承自 Widget.Material.Button 即可


GitHub Page: kniost.github.io
简书://www.greatytc.com/u/723da691aa42

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355

推荐阅读更多精彩内容