美文网首页Android知识Android开发Android
深入理解Android之Attr&Style&T

深入理解Android之Attr&Style&T

作者: absfree | 来源:发表于2016-09-05 18:17 被阅读794次

    先从是什么开始

    在日常开发中,我们会经常接触到Attr、Style、Theme这三个概念,但许多小伙伴一直对它们一知半解,在深入了解之前,这里先给出它们三者的基本定义。

    • Attr:属性(Attribute),用于指定UI的某种风格样式,比如android:layout_width就是一种Attr;
    • Style:风格,一系列Attr的集合,用于为UI指定一个“复合风格样式”;
    • Theme:主题,与Style的作用一样,区别于Style的作用范围是View,而Theme的作用范围是Activity或Application。

    接下来我们来逐一详细介绍Attr、Style与Theme。

    Attr

    Framework中的Attr

    我们在平时的开发中,更多的是使用Attr,只有在自定义View时才会定义Attr。Attr的定义很简单,我们拿平常经常使用的android:layout_xxx属性来举例,看看Android Framework中是如何定义Attr的。(取自<Android API 23 Platform>)

    <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>    
    
        <attr name="layout_height" format="dimension">        
            <enum name="fill_parent" value="-1" />        
            <enum name="match_parent" value="-1" />       
            <enum name="wrap_content" value="-2" />    
        </attr>
    </declare-styleable>
    

    从以上代码中我们可以看到,layout_xxx属性的取值范围为三个枚举值,其中使用fill_parent和match_parent是等价的,因为他们的value相同,之所以保留fill_parent,是为了兼容老版本。format表示了Attr的类型,可取的值有以下类型:

    • color:颜色值,如#000000
    • reference:引用某一资源ID。如@drawable/xxx
    • boolean:布尔值,true或false
    • dimension:尺寸值,可以为wrap_content、match_parent或是具体大小(xx dp)
    • float:浮点型
    • fraction:百分数
    • integer:整型
    • string:字符串类型
    • enum:枚举类型,各个取值互斥
    • flag:标记位,各个取值可用“|”连接

    接下来,我们来看下LinearLayout的showDividers属性的定义:

    <attr name="showDividers">    
      <flag name="none" value="0" />    
      <flag name="beginning" value="1" />    
      <flag name="middle" value="2" />    
      <flag name="end" value="4" />
    </attr>
    

    我们可以看到,它的取值有四种。那么问题来了,enum与flag标签的区别是什么呢?正如我们上面所提到的,这两者的区别在于flag的几个取值不互斥,而enum的几个取值是互斥的。

    自定义Attr

    自定义Attr十分简单,只需要在res/values目录下新建一个attrs.xml,然后仿照Framework中的定义即可,这里我们定义一个名为MyStyle的属性组:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
      <declare-styleable name="MyStyle">    
          <attr name="myName" format="string" />        
          <attr name="myWeight" format="integer" />
          <attr name="myPhoto" format="reference" />
      </declare-styleable>
    </resources>
    

    使用Attr

    我们在布局文件中这样使用自定义Attr:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout   
        xmlns:android="http://schemas.android.com/apk/res/android"          
        xmlns:myview="http://schemas.android.com/apk/res-auto/com.example.customview"> 
        <com.example.customview.MyView 
            myview:myName="absfree"
            myview:myWeight="66"
            myview:myPhoto="@drawable/absfree" />
    </LinearLayout>
    

    使用自定义Attr时我们要自定义一个命名空间,上例中我们自定义的命名空间为myview,com.example.customview为我们的自定义View类所在包。

    获取自定义Attr

    一种常见的在自定义View类中获取Attr的代码是这样的:

    public MyView(Context context, AttributeSet attrs) {
      super(context, attrs);
      TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyStyle);
      String name = ta.getString(R.styleable.MyStyle_myName, "absfree");
       . . .
    } 
    

    而上面代码中的obtainStyledAttributes方法最终调用的是以下重载版本的方法:

    public final TypedArray obtainStyledAttributes (AttributeSet set, int[] attrs, 
        int defStyleAttr, int defStyleRes)
    

    我们来解释以下这个方法四个参数的含义:

    • set:属性集,会传入到自定义View的构造器中,它保存了布局文件中为View指定的所有属性
    • attrs:想要获取的属性
    • defStyleAttr:表示一个指向Style的类型为reference的Attr
    • defStyleRes:表示Style的资源ID

    后两个参数都用于指定默认Style,当从attrs中找不到我们想要获取的属性时,就会使用默认Style,其中defStyleAttr的优先级高于defStyleRes。

    Style

    自定义Style

    在res/values/styles.xml的<resources>标签内增加如下内容:

    <style name="MyStyle"> 
        <item name="myName">absfree</item> 
        <item name="myWeight">66</item> 
        <item name="myPhoto">@drawable/absfree</item>
    </style>
    

    如此一来,我们便定义了一个名为MyStyle的Style,接下来我们看看如何使用它。

    使用自定义Style

    使用自定义Style与使用自定义Attr相仿:

    <com.example.customview.MyView 
            style="@style/MyStyle"
            . . . />
    

    如此一来,在MyView类中,我们便可以通过Theme的obtainStyledAttributes获取到自定义Style的值。比如以下代码可以后去到MyStyle中的myName的值。

    final Resources.Theme theme = context.getTheme();
    TypedArray ta = theme.obtainStyledAttributes(attrs, R.styleable.MyStyle, 
        defStyleAttr, defStyleRes);
    String name = ta.getString(R.styleable.MyStyle_myName);
    ta.recycle();
    

    这里的obtainStyledAttributes方法即为我们上面获取Attr时使用的方法。

    Theme

    自定义Theme

    自定义Theme的方法与自定义Style相同,也使用<style>标签。

    使用Theme

    要使用一个自定义Theme,我们只需要在AndroidManifest.xml文件的<Application>标签或是<Activity>标签中指定一个android:theme属性。设置完毕后,这个应用下的所有View或是相应Activity下的所有View就都可以使用相应Theme中的属性了。

    有一点需要注意的是,若想把我们自定义的Theme设置给Activity或Application,需要让我们的自定义Theme继承自一个系统Theme,否则会抛出IllegalStateException异常。

    <style name="MyStyle" parent="Theme.AppCompat"> 
        <item name="myName">absfree</item> 
        <item name="myWeight">66</item> 
        <item name="myPhoto">@drawable/absfree</item>
    </style>
    

    Style的优先级要高于Theme,如此一来我们可以先定义整个应用的整体风格样式,然后可以根据需要对局部风格样式做出个性化修改。

    获取Theme中的Attr

    在xml文件中获取Theme中Attr的语法如下:

    ?[<package_name>:][<resource_type>/]<resource_name>
    

    若是本应用中的Attr,则可以省去<package_name>。
    比如,我们向把TextView的text指定为MyStyle中的myName,只需按如下设置:

    <TextView 
        . . .
        android:text="?attr/myName"/>
    

    参考资料

    1. Android自定义View属性的相关细节
    2. 深入理解Android中的自定义属性
    3. Attr、Style和Theme详解

    **长按或扫描二维码关注我们,让您利用每天等地铁的时间就能学会怎样写出优质app。 **


    相关文章

      网友评论

        本文标题:深入理解Android之Attr&Style&T

        本文链接:https://www.haomeiwen.com/subject/bjofettx.html