Android View(四)-View相关属性详解

    我们在使用自定义View的时候,可能会遇到AttributeSet,TypedArray,declare-styleable等一些属性,那么今天我们就仔细看看这些属性是什么意思。

一.AttributeSet

1.我们先看看sdk文档是怎么说的。

A collection of attributes, as found associated with a tag in an XML document.
 Often you will not want to use this interface directly, instead passing it to Resources.
 Theme.obtainStyledAttributes() which will take care of parsing the attributes for you. 
 In particular, the Resources API will convert resource references 
 (attribute values such as "@string/my_label" in the original XML) to the desired type for you; 
 if you use AttributeSet directly then you will need to manually check for resource references 
 (with getAttributeResourceValue(int, int)) and do the resource lookup yourself if needed.
 Direct use of AttributeSet also prevents the application of themes and styles when retrieving attribute values.

是一个属性集合,在xml文档中与一个标签联合在一起。通常,你不会想直接使用这个接口,替代的,是把它传递给Resources.Theme.obtainStyledAttributes()这个方法,这个方法将为你解析里面的属性。具体地,Resources API 将转化资源引用(属性值例如 "@string/my_label" 在原始的xml)为你需要的类型;如果你直接使用AttributeSet ,那么需要你手动检查资源引用(使用getAttributeResourceValue(int, int))和资源查找如果你自己需要。直接使用AttributeSet 可能阻塞应用的主题和风格当在获取属性值的时候。

This interface provides an efficient mechanism for retrieving data from compiled XML files, 
 which can be retrieved for a particular XmlPullParser through Xml.asAttributeSet(). 
 Normally this will return an implementation of the interface that works on top of 
 a generic XmlPullParser, however it is more useful in conjunction with compiled XML resources:
 XmlPullParser parser = resources.getXml(myResource);
 AttributeSet attributes = Xml.asAttributeSet(parser);

这个接口提供了一些有效的功能用来从已编译的xml文件中获取数据,它是由Xml.asAttributeSet()传递一个特定的XmlPullParser获取到。通常情况下,它将返回一个基于通用XmlPullParser之上的接口实现,然而,它更有用的是结合已编译的xml资源。

The implementation returned here, unlike using the implementation on top of a generic XmlPullParser, 
is highly optimized by retrieving pre-computed information that was generated by aapt 
when compiling your resources. For example, the getAttributeFloatValue(int, float)
 method returns a floating point number previous stored in the compiled resource 
 instead of parsing at runtime the string originally in the XML file.

This interface also provides additional information contained in the 
compiled XML resource that is not available in a normal XML file, 
such as getAttributeNameResource(int) which returns the resource 
identifier associated with a particular XML attribute name.

实现返回这里,不像用在通用XmlPullParser之上的实现,是高度优化由aapt检索预计算信息当编译你的资源。例如,getAttributeFloatValue(int, float)这个方法返回一个浮点数存储在之前的已编译的资源上,而不是在运行时解析原始的xml文件的字符串。

这个接口还提供了额外信息包含在已编译的xml资源不可用在正常的xml文件,例如getAttributeNameResource(int)返回一个特定xml属性名称关联的资源标识符。

2.再看看源码。

public interface AttributeSet {
    /**
     * Returns the number of attributes available in the set.
     * 
     * @return A positive integer, or 0 if the set is empty.
     */
    public int getAttributeCount();
    ...
    /**
     * Return the integer value of attribute at 'index' that is formatted as an
     * unsigned value.  In particular, the formats 0xn...n and #n...n are
     * handled.
     * 
     * @param index Index of the desired attribute, 0...count-1.
     * @param defaultValue What to return if the attribute isn't found.
     * 
     * @return Resulting value.
     */
    public int getAttributeUnsignedIntValue(int index, int defaultValue);
    /**
     * Return the float value of attribute at 'index'.
     * 
     * @param index Index of the desired attribute, 0...count-1.
     * @param defaultValue What to return if the attribute isn't found.
     * 
     * @return Resulting value.
     */
    public float getAttributeFloatValue(int index, float defaultValue);

    /**
     * Return the value of the "id" attribute or null if there is not one.
     * Equivalent to getAttributeValue(null, "id").
     * 
     * @return The id attribute's value or null.
     */
    public String getIdAttribute();
    /**
     * Return the value of the "class" attribute or null if there is not one.
     * Equivalent to getAttributeValue(null, "class").
     * 
     * @return The class attribute's value or null.
     */
    public String getClassAttribute();

    ...
}

这个就是的AttributeSet接口的定义。

根据官网的说明,我们可以得知AttributeSet是这样得出的,

XmlPullParser parser = resources.getXml(myResource);
 AttributeSet attributes = Xml.asAttributeSet(parser);
那么我们再看看xml.asAttributeSet(XmlPullParser parser)是怎么实现的,

 public static AttributeSet asAttributeSet(XmlPullParser parser) {
        return (parser instanceof AttributeSet)
                ? (AttributeSet) parser
                : new XmlPullAttributes(parser);
    }
返回了一个AttributeSet实现。

XmlPullAttributes实现AttributeSet接口,它有一个构造方法是传递XmlPullParser参数,具体看看代码,

class XmlPullAttributes implements AttributeSet {
    public XmlPullAttributes(XmlPullParser parser) {
        mParser = parser;
    }
    public int getAttributeCount() {
        return mParser.getAttributeCount();
    }

    public String getAttributeName(int index) {
        return mParser.getAttributeName(index);
    }

    public String getAttributeValue(int index) {
        return mParser.getAttributeValue(index);
    }

    public String getAttributeValue(String namespace, String name) {
        return mParser.getAttributeValue(namespace, name);
    }

    public String getPositionDescription() {
        return mParser.getPositionDescription();
    }
    ...
    /*package*/ XmlPullParser mParser;
}

代码比较简单,从传递进来的参数XmlPullParser获取相应的值。

至此,通过上面描述,我们可以得知AttributeSet包含了我们在xml文件中定义的属性以及属性值,是一个集合!

二.TypedArray

1.首先看看sdk文件的介绍。

Container for an array of values that were retrieved with 
obtainStyledAttributes(AttributeSet, int[], int, int) or obtainAttributes(AttributeSet, int[]). 
Be sure to call recycle() when done with them. The indices used to retrieve values from this
structure correspond to the positions of the attributes given to obtainStyledAttributes.

一个数组容器,其值是从obtainStyledAttributes(AttributeSet, int[], int, int)或者obtainAttributes(AttributeSet, int[])获取的(这两个方法的参数都有AttributeSet)。一定要记得在使用完时调用recycle() 方法。该索引用于从结构相应位置的属性获取值兵赋值给obtainStyledAttributes。

2.源码示例。
public class TypedArray {

private final Resources mResources;
    /*package*/ XmlBlock.Parser mXml;
    /*package*/ int[] mRsrcs;
    /*package*/ int[] mData;
    /*package*/ int[] mIndices;
    /*package*/ int mLength;
    /*package*/ TypedValue mValue = new TypedValue();
  /**
     * Return the number of values in this array.
     */
    public int length() {
        return mLength;
    }
    
    /**
     * Return the number of indices in the array that actually have data.
     */
    public int getIndexCount() {
        return mIndices[0];
    }
    
    /**
     * Return an index in the array that has data.
     * 
     * @param at The index you would like to returned, ranging from 0 to
     * {@link #getIndexCount()}.
     * 
     * @return The index at the given offset, which can be used with
     * {@link #getValue} and related APIs.
     */
    public int getIndex(int at) {
        return mIndices[1+at];
    }
...
}
里面就是一些get方法。

三.declare-styleable

1.我们先看看官网是怎么介绍的。

 To define custom attributes, add <declare-styleable> resources to your project.
 It's customary to put these resources into a res/values/attrs.xml file. 
 Here's an example of an attrs.xml file:

<resources>
   <declare-styleable name="PieChart">
       <attr name="showText" format="boolean" />
       <attr name="labelPosition" format="enum">
           <enum name="left" value="0"/>
           <enum name="right" value="1"/>
       </attr>
   </declare-styleable>
</resources>
This code declares two custom attributes, showText and labelPosition, that belong to 
a styleable entity named PieChart. The name of the styleable entity is, 
by convention, the same name as the name of the class that defines the custom view.
 Although it's not strictly necessary to follow this convention, many popular 
 code editors depend on this naming convention to provide statement completion.

为了定义自定义属性,需要在你的项目中添加< declare-styleable >资源。通常,把这些资源放在res/values/attrs.xml文件中。一个attrs.xml 文件的例子:...

这段代码声明了2个自定义属性, showText 和 labelPosition,属于一个名叫PieChart的样式实体。样式实体的名字,通常情况,名字与自定义View的类名字一样。尽管这不是必须严格遵循的约束,许多流行的代码编辑器都依赖这个命名规则提供语法。

我们看看android framework源码attrs.xml的代码中是如何使用的,

        <declare-styleable name="TextView">
        ...
        <!-- Text color. -->
        <attr name="textColor" />
        <!-- Color of the text selection highlight. -->
        <attr name="textColorHighlight" />
        <!-- Color of the hint text. -->
        <attr name="textColorHint" />
        <!-- Base text color, typeface, size, and style. -->
        <attr name="textAppearance" />
        <!-- Size of the text. Recommended dimension type for text is "sp" for scaled-pixels (example: 15sp). -->
        <attr name="textSize" />
        <!-- Sets the horizontal scaling factor for the text. -->
        <attr name="textScaleX" format="float" />
        <!-- Typeface (normal, sans, serif, monospace) for the text. -->
        <attr name="typeface" />
        <!-- Style (bold, italic, bolditalic) for the text. -->
        <attr name="textStyle" />
        <!-- Text color for links. -->
        <attr name="textColorLink" />
        <!-- Makes the cursor visible (the default) or invisible. -->
        <attr name="cursorVisible" format="boolean" />
        <!-- Makes the TextView be at most this many lines tall. -->
        <attr name="maxLines" format="integer" min="0" />
        <!-- Makes the TextView be at most this many pixels tall. -->
        <attr name="maxHeight" />
        <!-- Makes the TextView be exactly this many lines tall. -->
        <attr name="lines" format="integer" min="0" />
        <!-- Makes the TextView be exactly this many pixels tall.
             You could get the same effect by specifying this number in the
             layout parameters. -->
        <attr name="height" format="dimension" />
        <!-- Makes the TextView be at least this many lines tall. -->
        <attr name="minLines" format="integer" min="0" />
        <!-- Makes the TextView be at least this many pixels tall. -->
        <attr name="minHeight" />
        <!-- Makes the TextView be at most this many ems wide. -->
        <attr name="maxEms" format="integer" min="0" />
        <!-- Makes the TextView be at most this many pixels wide. -->
        <attr name="maxWidth" />
        <!-- Makes the TextView be exactly this many ems wide. -->
        <attr name="ems" format="integer" min="0" />
        <!-- Makes the TextView be exactly this many pixels wide.
             You could get the same effect by specifying this number in the
             layout parameters. -->
        <attr name="width" format="dimension" />
        <!-- Makes the TextView be at least this many ems wide. -->
        <attr name="minEms" format="integer" min="0" />
        <!-- Makes the TextView be at least this many pixels wide. -->
        <attr name="minWidth" />
        ...
    </declare-styleable>
	 <declare-styleable name="TextViewAppearance">
        <!-- Base text color, typeface, size, and style. -->
        <attr name="textAppearance" />
    </declare-styleable>
	...

 <declare-styleable>标签是用来定义View的属性,用于我们在使用该View时设置属性!所以我们在自定义View已经属性时会使用到。在使用该标签设置属性时,需要format来指定属性的类型,属性的类型大概有以下几种,

1. reference:资源引用。
2. color:颜色值。
3. boolean:布尔值。
4. dimension:尺寸值。
5. float:浮点值。
6. integer:整型值。
7. string:字符串。
8. fraction:百分数。
9. enum:枚举值。
10. flag:位或运算。
经过上面描述,我们大概已经对这三个常用属性或者标签有所了解,接下来我们通过TextView的源码看看这些属性具体是怎么使用的。

四.TextView

1.源码。

public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {
        ...
        public TextView(Context context,
                    AttributeSet attrs,
                    int defStyle) {
        super(context, attrs, defStyle);
         ...
         //获取该View的主题
        final Resources.Theme theme = context.getTheme();
        /*
         * Look the appearance up without checking first if it exists because
         * almost every TextView has one and it greatly simplifies the logic
         * to be able to parse the appearance first and then let specific tags
         * for this View override it.
         */
        //根据官网的提示,通过obtainStyledAttributes获取TypedArray 
        TypedArray a = theme.obtainStyledAttributes(
                    attrs, com.android.internal.R.styleable.TextViewAppearance, defStyle, 0);
        TypedArray appearance = null;
		//通过index获取某一属性值
        int ap = a.getResourceId(
                com.android.internal.R.styleable.TextViewAppearance_textAppearance, -1);
        a.recycle();//使用完毕,调用recycle()
        if (ap != -1) {
		//这个应该是设置TextView的一些默认属性
            appearance = theme.obtainStyledAttributes(
                    ap, com.android.internal.R.styleable.TextAppearance);
        }
		//通过属性获取属性值
        if (appearance != null) {
            int n = appearance.getIndexCount();
            for (int i = 0; i < n; i++) {
                int attr = appearance.getIndex(i);

                switch (attr) {
                case com.android.internal.R.styleable.TextAppearance_textColorHighlight:
                    textColorHighlight = appearance.getColor(attr, textColorHighlight);
                    break;
              
                case com.android.internal.R.styleable.TextAppearance_textColor:
                    textColor = appearance.getColorStateList(attr);
                    break;
              
                case com.android.internal.R.styleable.TextAppearance_textColorHint:
                    textColorHint = appearance.getColorStateList(attr);
                    break;
                
                case com.android.internal.R.styleable.TextAppearance_textColorLink:
                    textColorLink = appearance.getColorStateList(attr);
                    break;
               
                case com.android.internal.R.styleable.TextAppearance_textSize:
                    textSize = appearance.getDimensionPixelSize(attr, textSize);
                    break;

                case com.android.internal.R.styleable.TextAppearance_typeface:
                    typefaceIndex = appearance.getInt(attr, -1);
                    break;

                case com.android.internal.R.styleable.TextAppearance_textStyle:
                    styleIndex = appearance.getInt(attr, -1);
                    break;

                case com.android.internal.R.styleable.TextAppearance_textAllCaps:
                    allCaps = appearance.getBoolean(attr, false);
                    break;
                }
            }
            appearance.recycle();
       ...
}
}

代码比较多,只罗列了TextView的三个参数的构造方法(不管你是在代码中new一个TextView或者是在xml布局文件中使用TextView,最终都是调用三个参数的构造方法)中的一点代码,AttributeSet attrs是从外部传递进来的(Xml.asAttributeSet(parser);),TypedArray是通过theme.obtainStyledAttributes()方法获取的,而textView的属性是从attrs.xml中定义的属性中获取的。

    至此,通过源码大致了解这几个属性的解释以及使用,相信你也有了新的认识!希望对大家有所帮助!(本人水平有限,有错误的地方,欢迎大家指出)








  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值