Android 中Style和Theme

概要

本文主要是对style和theme知识点的整理介绍,主要参考了Android Developers官方文档,介绍如何定义、使用style以及style实现继承的两种方式,最后介绍了如何设置主题以及针对不同版本平台如何差异化处理主题样式,如何切换主题实现夜间模式在本文中没有涉及,后续再重启一篇详细介绍。

style和theme在一起组合使用就可以确定我们一个App的外观UI,现在市场上很多App都带有夜间模式,像QQ这种非常注重用户体验的App他们的夜间模式都是在使用时才从网络下载下来的,这种方式可以有效的减少安装包的大小,像以上这些使用都是对style和theme的综合应用。只要我们前期可以很好的规划各种控件的style,最后就很容易开发出如同在网页中的换肤一样的效果。

Style样式

style是给View或Window指定外观和格式的属性集合。style能够指定如高、边距、字体颜色、字体尺寸、背景颜色等属性。它被定义在一个与布局xml文件分开的xml,资源文件中。
Android中的样式与web中的css样式类似,允许与内容分开设计。例如,通过使用样式,可以把下面这个布局xml转换成引用样式的声明:

不使用样式属性:

使用样式属性:

我们可以看到上面与布局相关的样式都从布局xml文件中删除了, 并且把这些样式放到了一个叫做CodeFont的XML样式定义中,然后把它设置给style属性。

定义style

如果要创建一个样式,就要把一个xml文件保存在项目目录res/values目录中,xml文件的名字可以随意,但是这个xml文件的根节点必须是<resources>

对于要创建的每个样式,都要在这个xml文件中添加一个<style>元素,并且name属性唯一的标识这个样式(这个属性是必须的),然后给样式的每个属性添加一个<item>元素,这个元素的name属性用于声明样式的属性名,属性值被放在一组<item>之间。给<item>元素的值能够是一个字符串、十六进制的颜色、另一个资源类型的引用、或者依赖样式属性的其他值,下例是一个单一样式的示例文件:

<resources>元素的每个子元素在编译时都要被转换成一个应用程序资源对象,通过<style>元素的name属性值来引用。这个示例的样式,在xml布局中使用@style/CodeFont来引用。<tyle>元素中的parent属性是可选的,它指定了另一个样式的资源ID,当前样式可以继承这个指定样式的属性,然后如果需要,可以覆写被继承的样式属性。

在xml中定义的一个样式style,它可以使用在一个View也可以作用于某个Activity或者整个应用Application,所以他们的样式style定义完全相同。

定义style时对于已有style的引用

  • 引用系统已有style,可以直接使用@android:style/系统样式名,如本例中parent="@android:style/Widget.TextView"或者如果是在布局文件中将parent改为style即可style="@android:style/Widget.TextView",下面情况类推;
  • 引用非系统自定义style,使用@style/自定义样式名,如parent="@style/CodeFont";
  • 如果引用主题属性attrs中的属性值,最常见的就是横向进度条,在布局文件引用时style="?android:attr/progressBarStyleHorizontal"
  • 如果引用自定义主题属性attrs中属性值,这种情况在app可以更换主题时非常常见, 如android:background="?attr/settingbackground"或者android:background="?settingbackground",两种形式都可以,settingbackground为自定义的一个主题属性<attr name="settingbackground" format="reference|color"/>;
  • 在style中每一个条目item的属性定义中,除了Android本身内置的属性添加命名空间android:xxx之外,其余的第三方包或者support包以及自定attrs中主题属性统统不需要添加命名空间来重置style。

Style的继承性

通过parent属性继承

Android中style的继承方式有两种情况,上面我们已经看到的一种就是通过parent属性继承一个已有的样式属性,可以继承自定义样式,也可以继承系统内置样式。例如,通过下面的方式更改了自定义文本字体的颜色。

通过点分开继承

该种方式仅适用于自定义样式,但是要把想要继承的样式名做新样式名的前缀(用点分开)。如,要创建一个新的继承上面定义的CodeFont样式的样式,但是要使用白色的文字,可以设计以下新样式:

注意在<style>标签中没有parent属性,但是因为name属性值用CodeFont样式名开始(这个样式已经被创建),所以这个样式会继承CodeFont样式定义的所有样式,然后它覆写了android:textColor属性,把文本设置为红色。使用@style/CodeFont.White来引用这个样式。

通过用点把名字连接方法,可以实现样式的层次继承,如可以把上面的CodeFont.White样式扩展成设置字体的样式:

这个样式继承了CodeFont和CodeFont.white样式,然后添加了android:textSize属性。

imagestyle

当把一个样式应用于布局中单一的View对象时,这个样式定义的属性只会用于这个View对象。如果样式被用于一个ViewGroup对象,那么其中的View子对象不会继承这个样式属性—样式只会用于直接引用该样式的元素。

主题

主题是应用在整个Activity或应用程序Application的样式,而不是一个独立的View对象。当一个样式被用作主题时,Activity或应用程序中的每个View对象都会使用它所支持的每个样式属性。例如,把相同的CodeFont样式用作一个Activity的主题,那么这个Activity内的所有文本都会使白色字体。

给Activity或应用程序应用主题

通过给Android清单文件中的<activity><application>元素添加android:theme属性,来给整个Activity或应用程序添加主题。

要给应用程序的所有Activity设置主题,就要在AndroidManifest.xml文件的<application>元素中包含android:theme属性,如:

如果要把一个主题只用于应用程序中的一个Activity,那么就要在<activity>>android:theme属性。跟Android提供的其他内置资源一样,有一些系统预定义的主题可以使用,因此要避免自己编写它们。例如,可以使用Dialog主题,让Activity的显示效果像一个对话框:

如果要使用一个主题,但需要调整,那么可以把这个主题作为定制主题的父主题。例如,可以修改传统的亮度主题,并添加自己想要的颜色:

上例中需要的颜色是用独立的资源提供的,这是因为android:windowBackground属性仅支持对另一个资源的引用,跟android:colorBackground不一样,它不能接收颜色值的设定。现在可以在Android清单文件内使用CustomTheme来替代Theme.Light

基于平台版本选择主题

比较新的Android版本中附带了一些应用程序可以利用的主题,并在这些平台上运行时,可能要使用这些主题,同时依然要兼容旧的版本。基于不同的平台版本,通过选择定制主题所使用的资源在不同的父主题之间的切换来达到兼容的目的。

比如android:windowTranslucentStatus属性只在Android4.4以上的版本才可以使用,那么如果在低版本中使用style文件中会报错,这时候我们要在res/values-19目录下新建一个xml文件来放入一个可选主题声明。

低版本主题设置:

Android4.4以上版本主题设置:

这样我们就可以像平常一样使用主题了,当Android版本在4.4及其以上时就会自动使用android:windowTranslucentStatus属性了。

本文地址www.sunnyang.com/347.html

参考资料

Styles and Themes

Difference between android:windowBackground and android:colorBackground?

Android xml资源文件中@、@android:type、@*、?、@+含义和区别

发表评论