在应用开发中,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" />
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类型泛指这两者。
style类型允许有继承关系,继承者自动拥有被继承style所拥有的属性。 style继承只允许继承自一个style,不支持多继承。
为了便于表述,这里把被继承的style称为parent style,新style称为child style。
在style继承时,child style自动继承parent style的所有属性。 同时,在child style中也可以重写parent style中的属性,还可以添加新的属性。
在style继承时,有两种方式可以指定其parent style。
第一种方式,通过“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>
大多数时候,我们在为属性指定属性值时,要么是直接给值,要么是引用一个资源。 而在引用资源时,通常是通过“@”来直接引用的(硬编码方式)。 还有另外一种资源引用方式,通过“?”动态引用当前已加载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" />
不论是在layout文件中,还是在style中,或者是在theme中为属性指定了值, 最终都需要在代码中读取出来。
当我们从layout文件inflate出View对象时,在View对象的构造过程中, 一般会调用Theme类的如下方法来读取该View所需要的相关属性值:
public TypedArray obtainStyledAttributes(AttributeSet set,
@StyleableRes int[] attrs, @AttrRes int defStyleAttr,
@StyleRes int defStyleRes)
这里,读取到的属性值有4个来源,并按下面的优先顺序来取值:
-
该AttributeSet中的属性值
-
该AttributeSet中“style”属性指定的style资源中的属性值
-
由defStyleAttr和defStyleRes参数指定的默认style中
-
当前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。
在Android中,theme和style没有本质上的不同,其定义方式是一样的,都是一个属性集合(可以是系统属性,也可以是自定义属性; 系统属性是指android.R.attr中定义的属性)。但在使用和工作机制上,还是有不少区别。
style的目标修饰对象是View,用于指定View的各种属性; 而theme的目标修饰对象是Activity或者Application, 并且影响Activity或者Application中的所有View。
有些系统属性仅适用于theme,不适用于style(也就是说,不能作用于View)。 例如,android.R.attr中以“window”为前缀的属性就是此类 (windowNoTitle、windowBackground,等等)。
也有些系统属性仅适用于style(或者说View),因为其并没有被添加到系统theme中。
💡
|
虽然在定义theme和style时,可以添加任意属性,但如果不能够被目标对象所理解, 那添加的多余属性是无意义的。 |
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在某种程度上可以满足对多继承支持的需求。 |
如果要创建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
为什么需要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" />
从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
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在命名上有统一的规则:
|
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。
-
在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">
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">
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">
在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">
属性 | 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或者更高) |
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 |
导航栏背景色 |
属性 | API Level | 属性描述 |
---|---|---|
android:colorPrimary |
21 & AppCompat |
品牌主颜色(例如,用作AppBar背景色) |
android:colorPrimaryDark |
21 & AppCompat |
StatusBar和上下文AppBar背景色 |
android:colorAccent |
21 & AppCompat |
焦点、激活等颜色(例如,widget的激活状态) |
属性 | API Level | 属性描述 |
---|---|---|
android:windowBackground |
1 |
用于作为window背景的drawable |
colorControlActivated |
21 |
android:widgets处于激活状态的颜色,默认值为 |
在工程实践中,一个项目现在或者将来可能会依赖其它带资源的库(例如,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">