专栏名称: 开发者全社区
分享和推送Java/Android方向的技术和文章,让你成为这方面的大牛,让你每天都成长一点。同时,我们也会邀请BAT的大牛分享原创!
目录
相关文章推荐
鸿洋  ·  画了10张图,带你搞定RecyclerVie ... ·  4 天前  
郭霖  ·  一篇文章带你彻底掌握Optional ·  5 天前  
郭霖  ·  一文了解 Gradle 的文件api ·  1 周前  
郭霖  ·  音视频基础能力之 Android ... ·  6 天前  
51好读  ›  专栏  ›  开发者全社区

Android Style你不知道的—Style 在 Android 中的继承关系

开发者全社区  · 公众号  · android  · 2017-03-05 13:02

正文

相关阅读:

吊炸天!74款APP完整源码!

安居客Android项目架构演进

[干货]2017已来,最全面试总结——这些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继承简介



<EditText

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

    ... />


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



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


两种继承方式混合的效果


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


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



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


import android.util.TypedValue;

import android.widget.TextView;

/**

* @author Ider

*/

public class StyledTextView extends TextView {

    public StyledTextView(Context context) {

        this(context, null);

    }

    public StyledTextView(Context context, AttributeSet attrs) {

        this(context, attrs, 0);

    }

    public StyledTextView(Context context, AttributeSet attrs, int defStyleAttr) {

        super(context, attrs, defStyleAttr);

        final TypedArray a = context.getTheme()

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

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

        final int color = a.getColor(R.styleable.CustomStyle_customColor, Color.RED);

        final float size = a.getDimensionPixelSize(R.styleable.CustomStyle_customSize, 70);

        a.recycle();

        setText(text);

        setTextColor(color);

        setTextSize(TypedValue.COMPLEX_UNIT_PX, size);

    }

}


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


    

    

    

    

    

resources>


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


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


运行之后得到效果如下:



第一个和第二个都是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.Holo和Theme.Holo.Light两个Style下。但因为Theme.Holo.Light用parent指定了其父Style是Theme.Light,所以Theme.Holo.Light并没有从Theme.Holo继承任何属性值,也因此这样的冗余是必须的。


看完本文有收获?请分享给更多人


Java和Android大牛频道

欢迎关注我们,一起讨论技术,扫描和长按下方的二维码可快速关注我们。搜索微信公众号:JANiubility。

公众号:JANiubility