文档开发者中心
我的

Android 主题设计全解析

Android主题设计!有点乱?
初学Android的时候对Android的主题设计都是处在一种模糊的认知状态,为啥呢?

自定义时候的attr,普通view的style属性,activity以及application的theme属性,theme与style定义的一致性以及theme的众多可选性,系统预置的style属性的继承与使用等等……

OK,先不管这些乱七八糟的,如果你对Android的主题设计依旧存在某些疑问,请看完这篇文章。


Theme、Style、Attr的基本概念


Attr:属性,风格样式的最小单元;

Style:风格,它是一系列Attr的集合用以定义一个View的样式,比如height、width、padding等;

Theme:主题,它与Style作用一样,不同于Style作用于个一个单独View,而它是作用于Activity上或是整个应用,并具有向下的覆盖特性


Theme
Theme的概念验证


好吧,为了清晰的验证上面的说法,我这里举个例子

新建一个moudle,在styles.xml中有如下内容


<resources> <!-- Base application theme. --> <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></resources>

可以看到该style定义了该主题下共享的三个颜色属性,以及继承了一个父主题
那么来看一下该主题应用的代码


<application android:allowBackup='true' android:icon='@mipmap/ic_launcher' android:label='@string/app_name' android:supportsRtl='true' android:theme='@style/AppTheme'> <activity android:name='.MainActivity'> <intent-filter> <action android:name='android.intent.action.MAIN' /> <category android:name='android.intent.category.LAUNCHER' /> </intent-filter> </activity> </application>

此时 ,这个默认主题应用在了Application下,我们启动模拟器观看主题效果

微信图片_20190808133735.png

普普通通没啥特别的,我们为前面的主题添加两个属性

<item name='windowActionBar'>false</item> <item name='windowNoTitle'>true</item>

重新启动模拟器,你看到了什么

微信图片_201908081337351.png

Activity的ActionBar被隐藏了,
是的,正如我前面所说,Theme一般应用于Application和Activity层级,并会继续向下覆盖,这里我们虽然只是设置了Application的theme属性,其下的所有Activity都会使用该主题。

Theme的定义
Theme的定义基本是一致的,主要是外部由一个一对style标签,内部通过item指明所定义的各个属性,下面的Theme就是一个标准的样例,

<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>

Theme的继承
1)通过parent属性进行系统主题的继承

<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>

2)通过“.”进行自定义主题的继承

<style name='AppTheme.NoActionbar'> <item name='windowActionBar'>false</item> <item name='windowNoTitle'>true</item> </style>

“.”前面是我们自定义的主题name,后面那就随意了,怎么写都可以了

style的继承与Theme一致,如果你原来不明白别人为何这样写,那么现在你肯定是知道了

Theme和Style的区别
定义上的区别:无太大区别,主要是属性不同,写法上基本一致
使用上的区别:
对于单个控件通过style进行引入(此时style不会向下覆盖);
对于Activity、Application等窗口级向下应用的通过theme进行引入;
使用系统预置的style
<!-- 使用系统预制style --><activity android:theme='@android:style/Theme.Dialog'><!-- 使用系统预制但局部修改的style --><activity android:theme='@style/CustomTheme'><color name='custom_theme_color'>#b0b0ff</color><style name='CustomTheme' parent='android:Theme.Light'> <item name='android:windowBackground'>@color/custom_theme_color</item> <item name='android:colorBackground'>@color/custom_theme_color</item></style>

使用Android系统内置的style,请务必加上“android:”

ThemeOverlays
在所有可用的主题中,我们可以发现一个名字带有 ThemeOverlay 的系列:
ThemeOverlay
ThemeOverlay.Light
ThemeOverlay.ActionBar.Light
ThemeOverlay.ActionBar.Dark
这些主题又是做什么的呢?答案是 仅用于为特定的用途定义必要的属性。

如果你不清楚,请看测试

我们首先创建两个toolbar的style

<style name='AppTheme.AppBar1' parent='ThemeOverlay.AppCompat.Light'/> <style name='AppTheme.AppBar2' parent='ThemeOverlay.AppCompat.Dark'/>

添加toolbar进行测试

<android.support.v7.widget.Toolbar android:id='@+id/toolbar' android:layout_width='match_parent' android:layout_height='?attr/actionBarSize' app:theme='@style/AppTheme.AppBar1' android:background='@color/colorPrimary'/>


微信图片_201908081337352.png

修改为第二个

微信图片_201908081337353.png

通过改变主题我们可以很轻松的实现界面的View的样式变换,是不是会很方便。

Theme的选用
其是很简单,在MD设计(也就是5.0)被推出之后,google推出了几个material的主题,但你不必去使用这些主题,因为有更好的替代方案
Theme.AppCompat
Theme.AppCompat.Light,
Theme.AppCompat.NoActionBar等等
这些主题既保证了向下的兼容又兼顾了material的主题设计,并与materiial的各个主题一一对应,你在选择的时候使用以Theme.AppCompat开头的主题准是没错。

那就有人问了,为毛线这么干,其他乱七八糟的主题又是啥呢?

这里我强烈推荐你看一篇文章(译文):android-themes-an-in-depth-guide

Attr
首先以layout_width为例分析自定义属性

<declare-styleable name='ViewGroup_Layout'> <attr name='layout_width' format='dimension'> <enum name='fill_parent' value='-1' /> <enum name='match_parent' value='-1' /> <enum name='wrap_content' value='-2' /> </attr></declare-styleable>

declare-styleable代表自定属性组,attr则是代表属性,name是属性的标识,format是该属性的值类型,内部为enum表示值是唯一的,只可选其一。

再来看一下text的style

<attr name='textStyle'> <flag name='normal' value='0' /> <flag name='bold' value='1' /> <flag name='italic' value='2' /></attr>

此时attr的内部是flag,代指属性值是可叠加使用的,比如textStyle = bold|italic则是加粗和斜体的叠加。

format属性的可选值如下
其中,reference代表引用,我们常用的@drawable/myImage、@color/myColor等都是这么干的。

ok,attr内部也只有enum和flag两种类型的属性,看完这个相信你可以自行定义属性了。


特别注意,当你的format选择错误的时候,填入对应的值AS并不会报错,所以具体实践时请留心

Attr的获得方法
有些情况下,我们可能需要使用theme中的属性值,比如下面我们想让一个TextView直接显示dogName这个属性的内容,并且使用系统字体的颜色,则可以如下做:

<TextView android:layout_width='wrap_content' android:layout_height='wrap_content' android:textColor='?android:textColorSecondary' android:text='?attr/dogName'/>

获得一个Attr的方法,不同于普通资源使用@符号获得的方式,而是需要使用?符号来获得属性,整体的表达方式如下:

?[:][/]
如果是本应用中的attr使用,则可以省去<package_name>部分。

此处的textColor使用当前主题的android:textColorSecondary属性内容。因为资源工具知道此处是一个属性,所以省去了attr (完整写法:?android:attr/textColorSecondary)。


Attr的使用优先级:View的Style>Activity的Theme>Application的Theme,所以说你可以定义整个应用的总体风格,但局部风格你也可以做出自己的调整。

最近做了下反思,与其制造网络垃圾不如不去写文章,所以准备大幅度降低写作速度并致力于提升文章的质量,未来计划在自己进步的同时分享进步的干货并不断去删除原文,以保证整个博客的文章质量和可用性。

如果你对本文有什么问题和看法请及时告知,送人玫瑰手有余香,谢谢支持。

参考文章:
Attr、Style和Theme详解
Android开发之Theme、Style探索及源码浅析
ThemeOverlay
Android Themes — An in-depth guide
---------------------
版权声明:本文为CSDN博主「月亮这么低」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:

点赞
2
收藏
4
回复
2
分享
举报
浏览1844 编辑于2019-08-08 05:42未知归属地
全部评论
最多点赞
最新发布
最早发布

大师在民间啊,膜拜一下!


2楼回复于2019-08-11 01:51 未知归属地

支持一下,我要早日成为元老级社区粉


1楼回复于2019-08-09 09:59 未知归属地
写回答
新增插入模板功能
一键使用模板,快速填写内容,轻松发帖~
知道了
  • 为了保障您的信息安全,请勿上传您的敏感个人信息(如您的密码等信息)和您的敏感资产信息(如关键源代码、签名私钥、调试安装包、业务日志等信息),且您需自行承担由此产生的信息泄露等安全风险。
  • 如您发布的内容为转载内容,请注明内容来源。

我要发帖子

了解社区公约,与您携手共创和谐专业的开发者社区。