深入理解 Android 之 Attr&Style&Theme

2,619 阅读4分钟

先从是什么开始

在日常开发中,我们会经常接触到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的。(取自)

    
            
               
                
            
        

            
                
               
            
    
  
    

从以上代码中我们可以看到,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属性的定义:

    
      
      
      
  

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

自定义Attr

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



      
              
      
      
  

  

使用Attr

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

 
    

使用自定义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的标签内增加如下内容:

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

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

使用自定义Style

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

如此一来,在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相同,也使用</code>标签。</p><h3>使用Theme</h3><p>要使用一个自定义Theme,我们只需要在AndroidManifest.xml文件的<Application>标签或是<Activity>标签中指定一个android:theme属性。设置完毕后,这个应用下的所有View或是相应Activity下的所有View就都可以使用相应Theme中的属性了。</p><p>有一点需要注意的是,若想把我们自定义的Theme设置给Activity或Application,需要让我们的自定义Theme继承自一个系统Theme,否则会抛出IllegalStateException异常。</p><pre><code><style name="MyStyle" parent="Theme.AppCompat"> <item name="myName">absfree</item> <item name="myWeight">66</item> <item name="myPhoto">@drawable/absfree</item>

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

获取Theme中的Attr

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

?[:][/]

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


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