Style在Android中的继承关系

Android的Styles(样式)和Themes(主题)非常类似Web开发里的CSS,方便开发者将页面内容和布局呈现分开。Style和Theme在Android里的定义方式是完全一样的,两者只是概念上的区别:Style作用在单个视图或控件上,而Theme用于Activity或整个应用程序。由于作用范围的不同,Theme也就需要比Style包含更多的定义属性值的项目(item)。不过本文,我将Style和Theme都归为Style来称呼。

Android的Style和Web的CSS相比,有一个缺陷就是只能针对一个对象只能通过android:theme="@style/AppTheme"style="@style/MyStyle"指定一个值。而CSS则可以通过class属性在DOM元素上定义多个样式来达到组合的效果。不过Style也有CSS没有的功能,那就是继承(Inheritance)。(当然CSS通过LESS和SASS这些工具也获得继承的能力。)

Style继承简介

根据Android Developers官方文档的介绍,定义Style的继承有两种方式:一是通过parent标志父Style;

  1. <style name="GreenText" parent="@android:style/TextAppearance">

  2. <item name="android:textColor">#00FF00</item>

  3. </style>

另一种则是将父Style的名字作为前缀,然后通过“.”连接新定义Style的名字:

  1. <style name="CodeFont.Red">

  2. <item name="android:textColor">#FF0000</item>

  3. </style>

第二种方式可以无限连接子Style来实践多层继承:

  1. <style name="CodeFont.Red.Big">

  2. <item name="android:textSize">30sp</item>

  3. </style>

相对第一种,Android对第二种方式做出的限制就是Style必须是由自己定义的,或者说父Style和子Style必须是定义在同一个程序内,不能是引用第三方或系统的Style。毕竟对于系统的Style的引用是需要加上android:前缀作为命名空间。

其次在使用Style时,对于第二种方式定义的Style,必须引用其完全的名字,也就是说必须要包含完整的前缀和名字:

  1. <EditText

  2. style="@style/CodeFont.Red.Big"

  3. ... />

Android对于第一种定义方式并没用限制,所以所有以第二种方式定义的Style都可以转用第一种:

  1. <style name="Big" parent="CodeFont.Red">

  2. <item name="android:textSize">30sp</item>

  3. </style>

只要parent中的名字对应上实际定义的Style名字即可。不过换成第一种后Style的名字如果太简洁就容易冲突了。

两种继承方式混合的效果

前面说到Style的两种继承方式的效果是一致的,那假如将两种方式混在一起定义一个Style又会是什么样的效果呢?下边就用实际例子来分析一下。

首先定义一些实验所需的自定义属性(attr),(这样可以减少系统属性的干扰,因为系统总是会为它的属性定义值,那样可能无法分辨最后的效果是来自系统还是定义的值)

  1. <?xml version="1.0" encoding="utf-8"?>

  2. <resources>

  3. <declare-styleable name="CustomStyle">

  4. <attr name="customColor" format="color"/>

  5. <attr name="customText" format="string"/>

  6. <attr name="customSize" format="dimension"/>

  7. </declare-styleable>

  8. </resources>

接着定义一个TextView的子类,并在其中获取上边自定义属性的值并赋予TextView去呈现:

  1. package com.ider.trial.styles;

  2. import android.content.Context;

  3. import android.content.res.TypedArray;

  4. import android.graphics.Color;

  5. import android.util.AttributeSet;

  6. import android.util.TypedValue;

  7. import android.widget.TextView;

  8. /**

  9. * @author Ider

  10. */

  11. public class StyledTextView extends TextView {

  12. public StyledTextView(Context context) {
  13. this(context, null);

  14. }

  15. public StyledTextView(Context context, AttributeSet attrs) {
  16. this(context, attrs, 0);

  17. }

  18. public StyledTextView(Context context, AttributeSet attrs, int defStyleAttr) {
  19. super(context, attrs, defStyleAttr);

  20. final TypedArray a = context.getTheme()

  21. .obtainStyledAttributes(attrs, R.styleable.CustomStyle, defStyleAttr, 0);

  22. final CharSequence text = a.getText(R.styleable.CustomStyle_customText);

  23. final int color = a.getColor(R.styleable.CustomStyle_customColor, Color.RED);
  24. final float size = a.getDimensionPixelSize(R.styleable.CustomStyle_customSize, 70);

  25. a.recycle();

  26. setText(text);

  27. setTextColor(color);

  28. setTextSize(TypedValue.COMPLEX_UNIT_PX, size);

  29. }

  30. }

然后就是定义研究所需的Style

  1. <resources>

  2. <style name="SuperStyleOne">

  3. <item name="customColor">@android:color/holo_orange_dark</item>

  4. <item name="customText">Hello World</item>

  5. <item name="customSize">30dp</item>

  6. </style>

  7. <style name="SuperStyleTwo">

  8. <item name="customText">www.iderzheng.com</item>

  9. </style>

  10. <style name="SuperStyleOne.SubOne">

  11. <item name="customColor">@android:color/holo_blue_dark</item>

  12. </style>

  13. <style name="SuperStyleOne.SubTwo" parent="SuperStyleTwo">

  14. </style>

  15. <style name="SuperStyleOne.SubThree" parent="SuperStyleTwo">

  16. <item name="customText">blog.iderzheng.com</item>

  17. </style>

  18. </resources>

上边定义的Style里,SuperStyleOne将通过添加前缀的方式作用到子Style上,而SuperStyleTwo则通过指定到parent来其作用。可以看到SubTwoSubThree混合了两种方式。

最后在Activity的布局视图里使用自定类并设定上不同的Style

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

  2. xmlns:tools="http://schemas.android.com/tools"

  3. android:orientation="vertical"

  4. android:layout_width="match_parent"

  5. android:layout_height="match_parent"

  6. android:paddingLeft="@dimen/activity_horizontal_margin"

  7. android:paddingRight="@dimen/activity_horizontal_margin"

  8. android:paddingTop="@dimen/activity_vertical_margin"

  9. android:paddingBottom="@dimen/activity_vertical_margin"

  10. tools:context=".MainActivity">

  11. <com.ider.trial.styles.StyledTextView

  12. style="@style/SuperStyleOne"

  13. android:layout_width="wrap_content"

  14. android:layout_height="wrap_content"/>

  15. <com.ider.trial.styles.StyledTextView

  16. style="@style/SuperStyleOne.SubOne"

  17. android:layout_width="wrap_content"

  18. android:layout_height="wrap_content"/>

  19. <com.ider.trial.styles.StyledTextView

  20. style="@style/SuperStyleOne.SubTwo"

  21. android:layout_width="wrap_content"

  22. android:layout_height="wrap_content"/>

  23. <com.ider.trial.styles.StyledTextView

  24. style="@style/SuperStyleOne.SubThree"

  25. android:layout_width="wrap_content"

  26. android:layout_height="wrap_content"/>

  27. </LinearLayout>

运行之后得到效果如下:

第一个和第二个都是Style标准的使用方式,也看到它们正确地获得了定义的属性值,子Style也正确的继承和覆盖了父Style的属性值。

对于第三个和第四个,它们呈现的颜色是代码中使用的默认红色(Color.RED),字体的值也是源自代码中的使用值,所以明显比前两者要小。这也就是说它们并没用继承下SuperStyleOne中定义的字体大小和颜色。但是SuperStyleTwo中定义的内容被第三个正确的显示了出来,也说明SubTwo成功继承通过parent指定的父Style的内容。而第四个呈现出来内容则说明覆盖的效果也是正确的。

在做这个试验之前,我一直以为两种方式会同时其作用,只是用parent指定比用前缀有高优先级。也就是说Android会先从当前Style定义中找某个属性的值,如果没有找到就转到parent指定的父Style中找,还没有则转到前缀指定的父Style中找。但是通过上边的结果表明:当使用parent指定父Style后,前缀方式则不在其作用,只是作为Style的名字。也就是说:Android的Style不支持多继承。Style的继承只能单线一层层下来。

反过来在看看系统定义的Style也更容易懂了,比如打开themes_holo.xml,会看到很多一样的内容被”冗余”地定义在Theme.HoloTheme.Holo.Light两个Style下。但因为Theme.Holo.Light用parent指定了其父Style是Theme.Light,所以Theme.Holo.Light并没有从Theme.Holo继承任何属性值,也因此这样的冗余是必须的。

  1. <style name="Theme.Holo.Light" parent="Theme.Light">

  2. ... ... ... ...

  3. </style>

使用Theme.Holo.Light作为Style的名字只是为了名字更加的清晰明了。

http://blog.iderzheng.com/android-style-inheritance/

Style在Android中的继承关系的更多相关文章

  1. android 中组件继承关系图,一目了然

    View继承关系图 Adapter适配器继承关系图 Activity继承关系图

  2. C++反汇编第四讲,反汇编中识别继承关系,父类,子类,成员对象

    C++反汇编第四讲,反汇编中识别继承关系,父类,子类,成员对象 讲解目录: 1.各类在内存中的表现形式   备注: 主要复习开发知识,和反汇编没有关系,但是是理解反汇编的前提.     2.子类继承父 ...

  3. 在Entity Framework 中实现继承关系映射到数据库表

    继承关系映射到数据库表中有多种方式: 第一种:TPH(table-per-hiaerachy) 每一层次一张表 (只有一张表) 仅使用名为父类的类型名的一张表,它包含了各个子类的所有属性信息,使用区分 ...

  4. Dom中的继承关系

    首先声明,一些内容基于个人猜测,如果哪里有错误,请立即联系在下! 我们用js操作Dom时,会经常用到一些个方法比如基于获取到的元素选择其子元素: <!DOCTYPE html> <h ...

  5. 初步学习C++中的继承关系

    继承机制是面向对象程序设计使代码能够复用的最重要的手段,它同意程序猿在保持原有类特性的基础上进行扩展,添加功能. 这样产生新的类,称派生类.继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂 ...

  6. c++中的继承关系

    1 什么是继承 面向对象的继承关系指类之间的父子关系.用类图表示如下: 2 为什么要有继承?/ 继承的意义? 因为继承是面向对象中代码复用的一种手段.通过继承,可以获取父类的所有功能,也可以在子类中重 ...

  7. 浅谈javaScript中的继承关系<一>

    // JavaScript Document //创建三个构造函数 function Shape(){ this.name='ahape'; this.toString=function(){retu ...

  8. java中的继承关系

    1.定义 java中的继承是单一的,一个子类只能拥有一个父类:java中所有类的父类是java.lang.Object,除了这个类之外,每个类只能有一个父类: 而一个父类可以有多个子类,可以被多个子类 ...

  9. 探究Android中通过继承ViewGroup自定义控件的原理

    原文地址:http://www.cnblogs.com/kross/p/3378395.html 今天断断续续的折腾了一下午到现在20:38,终于有点明白了.o(╯□╰)o 在Android开发中,我 ...

随机推荐

  1. Ubuntu安装deb时错误:“dpkg:错误:另外一个进程已经为 dpkg 状态数据库 加锁”解决

    以下方式任选一个即可: 1.重启系统 2.执行(这种方式不要尝试,系统很容易挂) sudo rm /var/lib/dpkg/lock 然后执行修复 sudo dpkg --configure -a

  2. 函数操作(this操作)

    1.apply/call函数:会改变this关键字,并且第一个参数作为this关键字. /*apply与call区别*/ console.log(Array.prototype.join.call([ ...

  3. MAPZONE GIS SDK接入Openlayers3之三——瓦片数据集接入

    瓦片数据集接入实现思路: 1.构造ol.source.TileImage数据源,构造该数据源需要以下几项: 1)空间参考,通过如下代码构造 2)TileGrid,构造需要以下几项: a)原点 b)分辨 ...

  4. 奇偶数对调,保持顺序 —— 剑指Offer

    这道题目 https://www.nowcoder.net/practice/beb5aa231adc45b2a5dcc5b62c93f593?tpId=13&tqId=11166&t ...

  5. iOS开发之剖析&quot;秘密&quot;App内容页面效果(一)

    近期在玩"秘密",发现点击主界面的Cell进去后的页面效果不错,就写了个Demo来演示下. 它主要效果:下拉头部视图放大,上拉视图模糊并且到一定位置固定不动,其它Cell能够继续上 ...

  6. React Native 中的component 的生命周期

    React Native中的component跟Android中的activity,fragment等一样,存在生命周期,下面先给出component的生命周期图 getDefaultProps ob ...

  7. POJ 1741 Tree 树形DP(分治)

    链接:id=1741">http://poj.org/problem?id=1741 题意:给出一棵树,节点数为N(N<=10000),给出N-1条边的两点和权值,给出数值k,问 ...

  8. Eclipse下单个文件中文乱码问题

    有时候用eclipse打开单个文件,会出现中文乱码问题. 这时可以点菜单栏 Edit -> Set Encoding,Other:UTF-8,通常可以解决问题.

  9. .NET下WebBrowser的一个BUG以及其替代品——geckofx

    今天研究一个小问题,在C#的WebBrowser下打开奇艺网的视频,经常整个FLASH就偏了,进度条控制条什么的都没有. 要全屏一下然后还原才能解决这个问题. 如下,图1为webbrowser打开,图 ...

  10. 第四周 Leetcode 124. Binary Tree Maximum Path Sum (HARD)

    124. Binary Tree Maximum Path Sum 题意:给定一个二叉树,每个节点有一个权值,寻找任意一个路径,使得权值和最大,只需返回权值和. 思路:对于每一个节点 首先考虑以这个节 ...