Skip to content

Latest commit

 

History

History
787 lines (607 loc) · 27.8 KB

0011-android-theme-and-style.asc

File metadata and controls

787 lines (607 loc) · 27.8 KB

Android Theme & Style

1. theme & style 介绍

1.1. 使用场景

在应用开发中,theme常用于在AndroidManifest.xml中修饰 application或者activity节点(如果没有指定,则会使用一个默认theme), 而style常用于在layout文件中修饰View节点。

在Android系统中,有很多系统定义的theme和style,可以直接使用。 也可以定义自己的theme和style:既可以全新定义, 也可以继承自其它theme和style(包括自定义的和系统定义的)。

例如,在AndroidManifest.xml中使用theme,通过“android:theme”属性设置:

<application
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme">
    <activity
        android:name=".DemoActivity"
        android:label="@string/app_name"
        android:theme="@style/AppTheme.NoActionBar" />
</application>

又如,在layout XML文件中使用style,通过“style”属性设置:

<TextView
    style="@style/MyWidget.XxxText"
    android:text="@string/hello" />

1.2. 如何定义

theme和style都是在res/values/目录中的xml资源文件中定义的(文件名随意), 其资源类型都为“style”。因此从语法层面,theme和style在定义时没任何区别。

style类型定义语法如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style
        name="style_name"
        parent="@[package:]style/style_to_inherit">
        <item
            name="[package:]style_property_name"
            >style_value</item>
        <!-- more items -->
    </style>
</resources>

从style类型定义的语法可以看到,style类型就是一个属性集合

示例代码:

<style name="MyWidget.XxxText" parent="@android:style/TextAppearance">
    <time name="android:layout_width">wrap_content</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:textColor">#00FF00</item>
    <item name="android:textSize">14sp</item>
</style>

为了便于表述,在后面讲theme和style,在不产生歧义的情况下, 会用style或者style类型泛指这两者。

1.3. 继承

style类型允许有继承关系,继承者自动拥有被继承style所拥有的属性。 style继承只允许继承自一个style,不支持多继承。

为了便于表述,这里把被继承的style称为parent style,新style称为child style。

在style继承时,child style自动继承parent style的所有属性。 同时,在child style中也可以重写parent style中的属性,还可以添加新的属性。

在style继承时,有两种方式可以指定其parent style。

1.3.1. 显示继承

第一种方式,通过“parent”属性显示指定parent style。示例代码如下:

<style name="MyWidget.XxxText" parent="@android:style/TextAppearance">
    <time name="android:layout_width">wrap_content</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:textColor">#00FF00</item>
    <item name="android:textSize">14sp</item>
</style>

在上面的示例代码中,定义了一个新的style “MyWidget.XxxText”, 并继承自系统style “@android:style/TextAppearance”。

在style继承时,由于"parent"属性的值只能是style类型, 因此可以把"@style/Xxxx”简化写成"Xxxx"。示例代码如下:

<style name="MyWidget.Xxx" parent="MyWidget.Yyy">
    ...
</style>

1.3.2. 隐式继承

第二种方式,通过“<parent style name>.”的前缀命名来隐式指定。示例代码如何:

<style name="MyWidget.XxxText.Big">
    <item name="android:textSize">18sp</item>
</style>

在上面的示例代码中,定义了一个新的style “MyWidget.XxxText.Big”, 其继承自style “MyWidget.XxxText”。

由于使用了名称前缀的指定方式,在应用开发中使用隐式继承时, 只能用于继承其它自定义style。

1.4. 引用属性

大多数时候,我们在为属性指定属性值时,要么是直接给值,要么是引用一个资源。 而在引用资源时,通常是通过“@”来直接引用的(硬编码方式)。 还有另外一种资源引用方式,通过“?”动态引用当前已加载theme中的属性的值。

例如,在定义style类型时(可以是styles也可以是themes), 动态引用当前已加载theme中的属性的值:

<style name="MyWidget.AbsListView">
    <item name="android:scrollbars">vertical</item>
    <item name="android:fadingEdge">vertical</item>
    <item name="android:fastScrollStyle">?android:attr/fastScrollStyle</item>
</style>

又如,在使用style时,动态引用当前已加载主题(theme)中的属性的值:

<Button
    android:id="@+id/btn1"
    style="?android:attr/buttonBarButtonStyle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

再如,在设置widget属性时,动态引用当前已加载主题(theme)中的属性的值:

<EditText
    android:id="@+id/edit1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textColor="?android:attr/textColorSecondary" />

由于引用属性时,一定是attr类型,因此可以不写资源类型。例如:

<EditText
    android:id="@+id/edit1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textColor="?android:textColorSecondary" />

1.5. 属性解析

不论是在layout文件中,还是在style中,或者是在theme中为属性指定了值, 最终都需要在代码中读取出来。

当我们从layout文件inflate出View对象时,在View对象的构造过程中, 一般会调用Theme类的如下方法来读取该View所需要的相关属性值:

public TypedArray obtainStyledAttributes(AttributeSet set,
    @StyleableRes int[] attrs, @AttrRes int defStyleAttr,
    @StyleRes int defStyleRes)

这里,读取到的属性值有4个来源,并按下面的优先顺序来取值:

  1. 该AttributeSet中的属性值

  2. 该AttributeSet中“style”属性指定的style资源中的属性值

  3. 由defStyleAttr和defStyleRes参数指定的默认style中

  4. 当前theme中的默认值

在View之外,我们也可以根据需要获取theme或者style中的属性。 例如,可调用Theme类的如下方法来读取当前theme中的属性值:

public TypedArray obtainStyledAttributes(@StyleableRes int[] attrs)

又如,调用Theme类的如下方法来读取指定style中的属性值:

public TypedArray obtainStyledAttributes(@StyleRes int resid,
    @StyleableRes int[] attrs)

前面几种方式都需要通过styleable间读取属性, 还可以调用Theme类的如下方法直接读取属性值:

public boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs)

这些方法的具体用法可参见 DefaultThemeDemo 项目中的AttributesTestActivity。

1.6. theme和style有何异同

在Android中,theme和style没有本质上的不同,其定义方式是一样的,都是一个属性集合(可以是系统属性,也可以是自定义属性; 系统属性是指android.R.attr中定义的属性)。但在使用和工作机制上,还是有不少区别。

1.6.1. 目标对象不同

style的目标修饰对象是View,用于指定View的各种属性; 而theme的目标修饰对象是Activity或者Application, 并且影响Activity或者Application中的所有View。

1.6.2. 属性集不同

有些系统属性仅适用于theme,不适用于style(也就是说,不能作用于View)。 例如,android.R.attr中以“window”为前缀的属性就是此类 (windowNoTitle、windowBackground,等等)。

也有些系统属性仅适用于style(或者说View),因为其并没有被添加到系统theme中。

💡
虽然在定义theme和style时,可以添加任意属性,但如果不能够被目标对象所理解, 那添加的多余属性是无意义的。

1.6.3. 工作机制不同

theme主要保存于Context中,每个View在构造时都会绑定一个Context, 并使用Context的theme来一同解析该View的属性(因为View的属性可以通过“?”引用theme中的属性)。 由于theme与context绑定关系,从而影响所有用到此Context的View对象。

而style仅是为了便于共享和统一管理View的若干个属性,在View构造时, View的“style”属性和其它属性会被一同解析(如果有同名属性,View显示指定的属性优先)。

1.7. ThemeOverlay

Android 5.0引入了一个新的特性,允许为View指定“android:theme”属性。

如果为View指定了“android:theme”属性,那么在inflate这个View时, “android:theme”属性指定的theme会叠加到当前context的theme之上。 因此,我们把View的“android:theme”属性指定的theme称为ThemeOverlay。

怎么理解“ThemeOverlay叠加到context theme”? context theme一般是一个有完整theme属性的style, 而ThemeOverlay仅是一个有若干个theme属性的style。 叠加时,ThemeOverlay中的属性会覆盖掉context theme中的同名属性。

💡
View的ThemeOverlay是通过ContextThemeWrapper实现的, 也可以阅读ContextThemeWrapper代码来理解这个叠加过程。

除了theme属性的叠加,“android:theme”还具有传播性: 为ViewGroup指定的ThemeOverlay会传播到子View中 (相当于为ViewGroup和所有子View设置了ThemeOverlay)。

💡
前面在讲style继承时说过,style不支持多继承, 但ThemeOverlay在某种程度上可以满足对多继承支持的需求。

1.7.1. 创建ThemeOverlay

如果要创建ThemeOverlay,可以继承已有的ThemeOverlay(API v21+):

  • ThemeOverlay:空theme,无属性

  • ThemeOverlay.Material:空theme,无属性

  • ThemeOverlay.Material.Light:颜色值为light版(不改变colorAccent,colorPrimary及其变种)

  • ThemeOverlay.Material.Dark:颜色值为dark版(不改变colorAccent,colorPrimary及其变种)

  • ThemeOverlay.Material.ActionBar

  • ThemeOverlay.Material.Dark.ActionBar

  • ThemeOverlay.Material.Dialog

  • ThemeOverlay.Material.Dialog.Alert

1.7.2. 应用场景

为什么需要ThemeOverlay,为什么不用style来解决? 这个问题可以从两方面来回答:

  • 有些属性仅存在于theme中,无法直接在View或者style的属性中指定。 若想在局部范围内改变这类属性的值,又不想完整定义一个新的theme,此时可以用ThemeOverlay来解决。

  • style作用于ViewGroup时无法传递到子View。

例如,Android 5.0的新增属性“android:colorEdgeEffect”,用于指定滚动到头的提示效果。 如果需要为某个单独的View定制不同的属性值,则需要通过为View设置一个ThemeOverlay来实现:

<style name="PinkThemeOverlay" parent="android:ThemeOverlay.Material">
    <item name="android:colorEdgeEffect">#FF4081</item>
</style>

<ListView
    ...
    android:theme="PinkThemeOverlay" />

1.7.3. AppCompat

从Android Support AppCompat v22.1.0开始,支持为任意View设置“android:theme”属性。 但对于API v10和更低版本,虽然可以使用“android:theme”属性,ThemeOverlay也能生效, 但子View无法承继Parent View的“android:theme”属性。

💡
AppCompat能够支持ThemeOverlay,是因为AppCompat使用了自定义的LayoutInflater。 而ThemeOverlay能够继承是通过LayoutInflater.Factory2来实现的, 而这个类是API v11才引入的。另外,为了支持tinting widgets,AppCompat重新实现了常见Widget, 并在其自定义LayoutInflater中自动把原生的widgets替换为AppCompat版本。

AppCompat对ThemeOverlay的支持是通过AppCompatDelegate来实现的。 因此,要么使用AppCompatActivity(其实现会调用AppCompatDelete), 要么直接使用AppCompatDelegate(参考AppCompatActivity的实现)。

如果使用了AppCompat,并且想使用ThemeOverlay,请继承AppCompat定义的ThemeOverlay: (最新的列表请参见AppCompat文档或者源码)

  • ThemeOverlay.AppCompat

  • ThemeOverlay.AppCompat.Light

  • ThemeOverlay.AppCompat.Dark

  • ThemeOverlay.AppCompat.ActionBar

  • ThemeOverlay.AppCompat.Dark.ActionBar

1.7.4. Theme vs ThemeOverlay vs Style

这三者可以从如下角度解读其差异:

  • Theme是一个全局的风格定义,影响Application或者Activity中的所有View

  • ThemeOverlay是一个小范围的风格定义,影响作用的View及所有子View

  • Style是一个最小范围的风格定义,仅影响作用的View

2. 系统Themes & Styles

2.1. Themes

Android为不同的应用场景,抽象并定义了一系列theme。 迄今为止,Android共推出了三套不同风格的theme: Old Theme, Holo Theme和Material Theme。

对于很多类别的theme,都有dark版本和light版本。 dark版指深色背景浅色文本,而light版指浅色背景深色文本。 在命名时,一般dark版是Theme.Xxx,而对应的light版则是Theme.Xxx.Light。

对系统的所有theme进行总结归纳,主要有如下类别:

  • base theme: 基础theme,适用于普通Activity。例如,Theme, Theme.Light, Theme.Holo, Theme.Holo.Light, Theme.Material,Theme.Meterial.Light。

  • NoActionBar theme: 适用于无需ActionBar的场景

  • Fullscreen theme: 适用于需要全屏的场景

  • Dialog theme: 适用于需要Dialog风格界面的场景

  • Panel theme: 适用于完全不需要window decoration的场景

  • Wallpaper theme: 适用于想半透显示桌面壁纸的场景

  • Overscan theme: 适用于TV,用于支持TV的overscan特性

  • TranslucentDecor theme: 适用于需要半透明状态栏和导航栏的场景

💡

从Holo Theme开始,所有theme和style在命名上有统一的规则:

  • 对于theme,采用“Theme.<theme family>.Etc”的命名方式。 例如,Theme.Holo, Theme.Material.Light, Theme.DeviceDefault.NoActionBar。

  • 对于style,采用“Type.<theme famliy>.Etc”的命名方式。 例如,Widget.Holo.Button, TextAppearance.DeviceDefault.Widget.Button。

2.1.1. DeviceDefault Theme

Android 4.0引入了一个特殊的theme “DeviceDefault”。 通常情况下,DeviceDefault本身只是一个theme alias (例如,在Android 4.0指向Holo theme,而在Android 5.0指向Material theme), 但设备厂商也可以对其进行修改来订制自己的风格(或者引用自己的风格)。 对应的,也有DeviceDefault系列style。

例如,在Android 5.0系统中,有如下DeviceDefault theme定义:

<style name="Theme.DeviceDefault" parent="Theme.Material">   <!-- since API v14 -->
<style name="Theme.DeviceDefault.Light" parent="Theme.Material.Light">

如果一个应用不指定要使用的theme,则系统需要为其加载一个默认theme。 默认加载哪个theme取决于两个因素: a) 应用的targetSdkVersion, b) 当前设备的API level。 具体规则如下:

  • 如果当前设备API level是API v10或者更低,则默认加载android.R.style.Theme;

  • 如果当前设备API level介于API 11和API 13之间,则默认加载android.R.style.Theme.Holo;

  • 如果当前设备API level是API v14或者更高,

    • 如果targetSdkVersion是API v10或者更低,则默认加载android.R.style.Theme;

    • 如果targetSdkVersion是介于API 11和API 13之间,则默认加载android.R.style.Theme.Holo;

    • 如果targetSdkVersion是API v14或者更高,则默认加载android.R.style.Theme_DeviceDefault。

2.1.2. Old Theme

在Android 3.0之前,系统只有一个theme系列,这里把它叫Old Theme, 以便与其它theme系列进行区分。

这里,列出了其中一些重要的theme:

<style name="Theme">    <!-- dark background & light text -->
<style name="Theme.NoTitleBar">
<style name="Theme.NoTitleBar.Fullscreen">
<style name="Theme.NoTitleBar.OverlayActionModes">

<style name="Theme.Light">   <!-- light background & dark text -->
<style name="Theme.Light.NoTitleBar">
<style name="Theme.Light.NoTitleBar.Fullscreen">

<style name="Theme.Black">   <!-- completely black background -->
<style name="Theme.Black.NoTitleBar">
<style name="Theme.Black.NoTitleBar.Fullscreen">

<style name="Theme.Wallpaper">
<style name="Theme.Wallpaper.NoTitleBar">
<style name="Theme.Wallpaper.NoTitleBar.Fullscreen">

<style name="Theme.Translucent">   <!-- transparent background & support translucent window & no window animation -->
<style name="Theme.Translucent.Fullscreen">
<style name="Theme.Translucent.OverlayActionModes">

<style name="Theme.WithActionBar">
<style name="Theme.NoDisplay">   <!-- for activities which don't actually display a UI -->

<style name="Theme.Dialog">
<style name="Theme.Dialog.NoFrame">   <!-- no window decorations -->
<style name="Theme.Dialog.Alert">

<style name="Theme.Panel">  <!-- no window decorations -->
<style name="Theme.Light.Panel">

<style name="Theme.InputMethod" parent="Theme.Panel">
<style name="Theme.SearchBar" parent="Theme.Holo.Light.Panel">
<style name="Theme.GlobalSearchBar" parent="Theme.Panel">
<style name="Theme.IconMenu" parent="Theme.Holo">
<style name="Theme.ExpandedMenu" parent="Theme.Holo">

2.1.3. Holo Theme

API v11引入了Holo Theme,在视觉风格上更加统一。

💡
在Holo Theme中,widgets的背景为半透明。因此要求在使用Holo Theme时, 需要关注设置的背景是否适当,否则可能导致看不清楚widgets。

这里,列出了其中一些重要的theme:

<style name="Theme.Holo">
<style name="Theme.Holo.NoActionBar">
<style name="Theme.Holo.NoActionBar.Fullscreen">
<style name="Theme.Holo.NoActionBar.Overscan">   <!-- for TV -->
<style name="Theme.Holo.NoActionBar.TranslucentDecor"> <!-- translucent system decor (status bar & navigation bar) -->

<style name="Theme.Holo.Light" parent="Theme.Light">
<style name="Theme.Holo.Light.DarkActionBar">
<style name="Theme.Holo.Light.NoActionBar">
<style name="Theme.Holo.Light.NoActionBar.Fullscreen">
<style name="Theme.Holo.Light.NoActionBar.Overscan">
<style name="Theme.Holo.Light.NoActionBar.TranslucentDecor">

<style name="Theme.Holo.Dialog">
<style name="Theme.Holo.Dialog.MinWidth">
<style name="Theme.Holo.Dialog.FixedSize">
<style name="Theme.Holo.Dialog.NoActionBar">
<style name="Theme.Holo.Dialog.NoActionBar.MinWidth">
<style name="Theme.Holo.Dialog.NoActionBar.FixedSize">
<style name="Theme.Holo.Dialog.NoFrame">
<style name="Theme.Holo.Dialog.Alert">

<style name="Theme.Holo.Light.Dialog">
<style name="Theme.Holo.Light.Dialog.MinWidth">
<style name="Theme.Holo.Light.Dialog.FixedSize">
<style name="Theme.Holo.Light.Dialog.NoActionBar">
<style name="Theme.Holo.Light.Dialog.NoActionBar.MinWidth">
<style name="Theme.Holo.Light.Dialog.NoActionBar.FixedSize">
<style name="Theme.Holo.Light.Dialog.Alert">

<style name="Theme.Holo.Wallpaper">
<style name="Theme.Holo.Wallpaper.NoTitleBar">

<style name="Theme.Holo.Panel">
<style name="Theme.Holo.Light.Panel">
<style name="Theme.Holo.InputMethod" parent="Theme.Holo.Light.Panel">
<style name="Theme.Holo.SearchBar" parent="Theme.Holo.Panel">
<style name="Theme.Holo.Light.SearchBar" parent="Theme.Holo.Light.Panel">

<style name="Theme.Holo.CompatMenu">
<style name="Theme.Holo.Light.CompatMenu">

2.1.4. Material Theme

API v21引入了Material Theme。在Material Theme中,主要增加了如下几类theme:

  • “Settings” theme

  • “Presentation” theme

  • “LightStatusBar” theme (API v23)

  • “ThemeOverlay” theme

这里,列出了其中一些重要的theme:

<style name="Theme.Material">
<style name="Theme.Material.Light" parent="Theme.Light">
<style name="Theme.Material.Light.DarkActionBar">
<style name="Theme.Material.Light.LightStatusBar">   <!-- light status bar background -->

<style name="Theme.Material.NoActionBar">
<style name="Theme.Material.NoActionBar.Fullscreen">
<style name="Theme.Material.NoActionBar.Overscan">
<style name="Theme.Material.NoActionBar.TranslucentDecor">
<style name="Theme.Material.Light.NoActionBar">
<style name="Theme.Material.Light.NoActionBar.Fullscreen">
<style name="Theme.Material.Light.NoActionBar.Overscan">
<style name="Theme.Material.Light.NoActionBar.TranslucentDecor">

<style name="Theme.Material.Dialog">
<style name="Theme.Material.Dialog.MinWidth">
<style name="Theme.Material.Dialog.FixedSize">
<style name="Theme.Material.Dialog.NoActionBar">
<style name="Theme.Material.Dialog.NoActionBar.MinWidth">
<style name="Theme.Material.Dialog.NoActionBar.FixedSize">
<style name="Theme.Material.Dialog.NoFrame">
<style name="Theme.Material.Dialog.Alert">

<style name="Theme.Material.Light.Dialog">
<style name="Theme.Material.Light.Dialog.MinWidth">
<style name="Theme.Material.Light.Dialog.FixedSize">
<style name="Theme.Material.Light.Dialog.NoActionBar">
<style name="Theme.Material.Light.Dialog.NoActionBar.MinWidth">
<style name="Theme.Material.Light.Dialog.NoActionBar.FixedSize">
<style name="Theme.Material.Light.Dialog.Alert">

<style name="Theme.Material.Panel">
<style name="Theme.Material.Light.Panel">
<style name="Theme.Material.InputMethod" parent="Theme.Material.Light.Panel">
<style name="Theme.Material.SearchBar" parent="Theme.Material.Panel" />
<style name="Theme.Material.Light.SearchBar" parent="Theme.Material.Light.Panel" />

<style name="Theme.Material.Voice" parent="Theme.Material.Dialog">
<style name="Theme.Material.Light.Panel" parent="Theme.Material.Light.Dialog">

<style name="Theme.Material.CompatMenu">
<style name="Theme.Material.Light.CompatMenu">

<style name="Theme.Material.Wallpaper">
<style name="Theme.Material.Wallpaper.NoTitleBar">

<!-- for settings -->
<style name="Theme.Material.Settings" parent="Theme.Material.Light.DarkActionBar">
<style name="Theme.Material.Settings.NoActionBar" parent="Theme.Material.Light.NoActionBar">
<style name="Theme.Material.Settings.Dialog">
<style name="Theme.Material.Settings.Dialog.Alert">
<style name="Theme.Material.Settings.Dialog.Presentation">

<!-- for presentation window on a secondary display -->
<style name="Theme.Material.Dialog.Presentation" parent="Theme.Material.NoActionBar.Fullscreen" />
<style name="Theme.Material.Light.Dialog.Presentation" parent="Theme.Material.Light.NoActionBar.Fullscreen" />

<!-- ThemeOverlay -->
<style name="ThemeOverlay" />   <!-- empty theme -->
<style name="ThemeOverlay.Material" />   <!-- empty theme -->
<style name="ThemeOverlay.Material.Light">   <!-- with light colors -->
<style name="ThemeOverlay.Material.Dark">   <!-- with dark colors -->
<style name="ThemeOverlay.Material.ActionBar">
<style name="ThemeOverlay.Material.Dark.ActionBar">

<style name="ThemeOverlay.Material.Dialog">
<style name="ThemeOverlay.Material.Dialog.Alert">

2.2. Styles

在Old Theme中,style一般采用“Type.Etc”的命名方式; 而从Holo Theme开始,style采用了“Type.<theme famliy>.Etc”的命名方式。 这里的“Type”有如下几类:

  • Animation

  • TextAppearance

  • Widget

例如:

<style name="Animation" />
<style name="Animation.Activity">

<style name="TextAppearance">
    <item name="textColor">?textColorPrimary</item>
    <item name="textColorHighlight">?textColorHighlight</item>
    <item name="textColorHint">?textColorHint</item>
    <item name="textColorLink">?textColorLink</item>
    <item name="textSize">16sp</item>
    <item name="textStyle">normal</item>
</style>
<style name="TextAppearance.Holo" parent="TextAppearance" />
<style name="TextAppearance.Holo.Widget.Button">

<style name="Widget">
    <item name="textAppearance">?textAppearance</item>
</style>
<style name="Widget.SeekBar">
<style name="Widget.Holo.Button" parent="Widget.Button">
<style name="Widget.Holo.Button.Small">

2.3. 属性

2.3.1. window相关属性

属性 API Level 属性描述

android:windowNoTitle

1

window是否有title bar

android:windowFullscreen

1

window是否全屏(如果全屏,一般也会设置window无title bar)

android:windowActionBar

11

window是否有action bar

android:windowActionBarOverlay

11

如果window有action bar,该action bar是否为overlay形式(覆盖内容区域之上)

android:windowActionModeOverlay

11

当没有action bar时,action mode是否为overlay形式(覆盖在内容区域之上)

android:windowContentOverlay

1

window内容区域之上绘制的Drawable,通常用于在title bar下显示阴影

android:windowIsFloating

1

该window是否悬浮(主要用于Dialog)

android:backgroundDimEnabled

3

是否dim当前window后面的区域

android:windowCloseOnTouchOutside

11

区域之外touch是否自动关闭window(targetSdkVersion需要API v11或者更高)

2.3.2. System Bars相关属性

system bars主要有status bar和navigation bar。

属性 API Level 属性描述

android:windowDrawsSystemBarBackgrounds

21

当前window是否负责绘制system bars的背景

android:windowTranslucentStatus

19

半透明status bar(启用后会导致当前window占用status bar区域,两者重叠)

android:statusBarColor

21

StatusBar背景色,默认继承android:colorPrimaryDark的值

android:windowLightStatusBar

23

标识是否启用light status bar

android:windowTranslucentNavigation

19

半透明navigation bar

android:navigationBarColor

21

导航栏背景色

2.3.3. 颜色和背景相关属性

Table 1. Material Design 相关属性
属性 API Level 属性描述

android:colorPrimary

21 & AppCompat

品牌主颜色(例如,用作AppBar背景色)

android:colorPrimaryDark

21 & AppCompat

StatusBar和上下文AppBar背景色

android:colorAccent

21 & AppCompat

焦点、激活等颜色(例如,widget的激活状态)

Table 2. 颜色和背景相关属性
属性 API Level 属性描述

android:windowBackground

1

用于作为window背景的drawable

colorControlActivated

21

android:widgets处于激活状态的颜色,默认值为

3. 工程实践

在工程实践中,一个项目现在或者将来可能会依赖其它带资源的库(例如,AppCompat或者一个第三方库)。 这可能会产生一个资源命名冲突的问题,一旦发生,就可能发生两方面的风险:

  • 一些冲突必须通过重命名解决(例如,attr和style等类型的冲突)

  • 在冲突时自动完成merge,而不被人发觉(例如,一些资源文件),但这个mege不是被期望发生的。

因此,在项目启动时(特别是作为第三方库的项目),在资源命名上要制定规范, 以尽最大可能避免潜在冲突。

在制定资源命名规范时,通行做法是通过公共前缀命名的方式来进行的。 例如, AndroidLib 项目的uiLib模块是一个公共UI库, 里面所有的资源名称都以“commonui”或者“commonui_”或者“CommonUi”为前缀:

<color name="commonui_divider_color">#00aaaa</color>
<dimen name="commonui_divider_margin">6dp</dimen>
<string name="commonui_tips_loading">Loading…</string>
<attr name="commonuiDividerMargin" format="dimension" />

<style name="CommonUiTheme.Light" parent="Theme.AppCompat.Light.DarkActionBar">
<style name="Widget.CommonUiTheme.ScrollView">