Android知识Android开发Android

深入理解Android之Attr&Style&T

2016-09-05  本文已影响794人  absfree

先从是什么开始

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

接下来我们来逐一详细介绍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的类型,可取的值有以下类型:

接下来,我们来看下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)

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

后两个参数都用于指定默认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。 **


上一篇下一篇

猜你喜欢

热点阅读