天天看点

Android自定义属性(一):自定义属性的使用如何自定义属性XML中使用自定义属性代码中使用自定义属性添加属性和事件

官方文档:https://developer.android.com/training/custom-views/create-view#java

如何自定义属性

  • 在res/values/attr.xml文件中添加<declare-stylable>标签,在该标签中添加自定义属性
  • 在xml布局中为属性指定值
  • 运行时检索属性值
  • 将检索到的属性值应用于视图

示例:

1、为了自定义属性,在项目中添加<declare-resource>资源,将该资源放置于res/values/attrs.xml。 如下是attrs.xml文件例子:

<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>
           

这段code定义了两个属性showText和lablePosition,属于PieChart实体。

代码的含义:
declare-styleable:一个属性组,其name必须和自定义View的名字相同。
attr:代表一个单独的属性,format代表属性的格式。
labelPosition属性中定义了默认值enum
           

XML中使用自定义属性

定义的属性和系统的其他内置属性一样在xml中使用。唯一的区别是它们所属的命名空间(namespace)不同。

内置属性所属的命名空间:http://schemas.android.com/apk/res/android

自定义属性所属命名空间:http://schemas.android.com/apk/res/[your package name]

例如,如下是如何为PieChart使用这些自定义的属性:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:custom="http://schemas.android.com/apk/res/com.example.customviews">
 <com.example.customviews.charting.PieChart
     custom:showText="true"
     custom:labelPosition="left" />
</LinearLayout>
           

xmlns:custom是加入命名空间,这个名称可以任意更改。如果修改为xmlns:xx,则使用属性时就是xx:showText = "true"。

注意此处的XML tag添加自定义view是完全限定名称。如果视图类是一个内部类,必须使用视图外部类的名称进一步限定它。

比如,PieChart有一个内部类叫做PieView,要使用此类中的自定义属性,可使用tag  com.example.customviews.charting.PieChart$PieView.

自定义属性的取值都是取决于自定义View的布局文件中的对应的属性的值。如showText属性就为true,labelPosition属性就为left。

代码中使用自定义属性

从XML布局创建视图时,XML tag中的所有属性都从资源包中读取,并作为AttributeSet传递到视图的构造函数中。虽然可以直接从AttributeSet中直接获取,但是这样做有一些缺点:

  • 属性中的资源引用没有解析
  • 样式没有被应用

相反,将AttributeSet传递给obtainStyleAttributes()。这个方法回传一个已经解析过的资源引用和应用了样式的TypedArray数组。

PieChart如何读取它的属性:

public PieChart(Context context, AttributeSet attrs) {
   super(context, attrs);
   TypedArray a = context.getTheme().obtainStyledAttributes(
        attrs,
        R.styleable.PieChart,
        0, 0);

   try {
       mShowText = a.getBoolean(R.styleable.PieChart_showText, false);
       mTextPos = a.getInteger(R.styleable.PieChart_labelPosition, 0);
   } finally {
       a.recycle();
   }
}
           

注意,TypedArray对象是共享资源,必须使用后进行回收。

添加属性和事件

属性是控制视图行为和显示的有效方法,但是只能在视图初始化后时读取它们。要提供动态行为,需要为每个自定义属性创建gettter和setter方法。如下代码,展示了PieChart如何公开属性showText:

public boolean isShowText() {
   return mShowText;
}

public void setShowText(boolean showText) {
   mShowText = showText;
   invalidate();
   requestLayout();
}
           

setShowText函数里调用了invalidate()和requestLayout()函数,这两个函数对于视图能正常地显示有至关重要的作用。如果改变了可能影响显示的属性,必须废止(invalidate)当前视图,这样系统才会知道需要重绘。同样,如果一个可能影响视图size或shape的属性改变了,需要申请新的布局。如果没有调用这个两个方法,可能会出现难以发现的Bug。

自定义视图应该要定义事件监听器来通知重要事件。例如,PieChart有一个自定义方法OnCurrentItemChanged来通知listener,用户旋转了这个Pie chart以关注新的Chart Slice。

继续阅读