如android官网所说的那样 creating custon view。http://developer.android.com/training/custom-views/index.html
android的framework 有大量的View 类用来和用户交互和展示各种类型的数据。但是有些时候通过内置的View你的app的一些独一无二的需求无法得到满足。接下去就介绍下如何创建强大、可复用的View。
创建一个View Class
subclass a view (创建一个view的子class
define custom attributes (定义特殊的属性
这边有几点要求:
1在你的resource <declare-styleable> 部分中为你自己的view定义特殊的属性
2在你的xml layout 中表明特殊的值
3运行时获取属性值
4将或得到的属性值赋予你的view
- Define custom attributes for your view in a
<declare-styleable>
resource element - Specify values for the attributes in your XML layout
- Retrieve attribute values at runtime
- Apply the retrieved attribute values to your view
添加<declare-styleable> resource到你的项目中可以定制一个特制的属性。下面是一个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>
上面这段代码定义了styleable 实体 PieChat 的两个特殊的特制属性 showText 和 labelPosition。
为了方便,styleable实体的名字和特制View类的名字一样。虽然这不是强制需要这样的,但是好的代码这样子写就会在语法上方便一点。
一但你定义了特制的属性,你就可以在layout xml文件中就像内置属性一样使用它们。唯一的不同之处就是你的特制的属性属于不同的命名空间。
特制的属性属于http://schemas.android.com/apk/res/[your package name] ,而不是属于http://schemas.android.com/apk/res/android命名空间。
举个例子,如何来为PieChat 定义属性:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<span style="color:#009900;">xmlns:custom="http://schemas.android.com/apk/res/com.example.customviews"</span>>
<com.example.customviews.charting.PieChart
custom:showText="true"
custom:labelPosition="left" />
</LinearLayout>
为了避免重复出现较长的命名空间的URL custom="url" 再采用 costom这个alias来引用 custom:showText。 所以你可以采用任何你想用的alias.。
注意,那个添加 custom view 至layout的xml tag,它是自定义视图的完全限定名称。如果你的custom view是一个内置类,你必须为他制定他的outer class,就是包含他的class。 举例 PieChat class 有一个inner class 叫做 PieView。为了使用这个类的属性,你必须使用com.example.customviews.chating.PieChar$PieView
Apply Custom Attributes 运用特制的属性
当一个View从 xml layout中创建的时候,xml tag中全部的attributes 就会从绑定的resource中读取出来,并且通过AttributeSet向view的Construcotr传递进去。
虽然可以从AttributeSet中直接读取数据,但是这么做会有以下几点危险的地方:
1 属性在资源引用中没有解决
2 样式不适用
- Resource references within attribute values are not resolved
- Styles are not applied
这个方法会返回一个 已经包含 dereferenced 和styled 值 的TypedArray类型 的数组。
This method passes back a TypedArray
array of values that have already been dereferenced and styled.
Android Resource 编译器为了让你调用 obtainStyledAttritues()方法更加方便,会给你做大量的工作。
在res 目录下面的每一个 <declare-styleable>部分,generated R.java 会为
the generated R.java defines both an array of attribute ids and a set of constants that define the index for each attribute in the array.
你直接使用先前就定义好的常量去TypedArray中读取attributes。这里展示PieChat类如何读取Attributes:
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对象是一个分享的资源,所以当你用完了以后必须要回收利用。
Add Properties and Events 添加属性和事件
Add Properities and Events
attributes是控制view行为和表现的一个强大的手段,但是他们只有在view被初始化的时候才能被读取。为了提供一个动态的行为表现,给每一个属性设置getter和setter
The following snippet shows how PieChart
exposes a property called showText
:
public boolean isShowText() {
return mShowText;
}
public void setShowText(boolean showText) {
mShowText = showText;
invalidate();
requestLayout();
}
注意,setShowText 调用了invalidate()和requestLayout()方法。这些方法被调用来确实view的行为表现是确时的。当你给view做了任何会影响它显示的属性改动时,你就应该 invalidateview,这样系统才会知道view需要被重新绘制。同样的,当view的一个属性改变时,可能会影响到它的尺寸或或者是形状,所以你需要重新请求一个layout。忘记调用这些方法会造成无法发现的错误。
特制的View应该同样支持事件的监听来和重要的事件进行交流。
For instance, PieChart
exposes a custom event called OnCurrentItemChanged
to notify listeners that the user has rotated the pie chart to focus on a new pie slice.
It's easy to forget to expose properties and events, especially when you're the only user of the custom view. Taking some time to carefully define your view's interface reduces future maintenance costs. A good rule to follow is to always expose any property that affects the visible appearance or behavior of your custom view.
- Label your input fields using the
android:contentDescription
attribute - Send accessibility events by calling
sendAccessibilityEvent()
when appropriate. - Support alternate controllers, such as D-pad and trackball