原文地址http://developer.android.com/training/custom-views/create-view.html
说在前面的话:第一次翻译,自知翻译得不是很好,所以请读者(如果有读者的话)不要责怪,我相信以后会做得更好的。
为什么我要去翻译,我想原因有以下几点吧:
- 锻炼我的英语阅读的能力
- 通过认真地翻译,让我可以对翻译的内容有更深入的了解,可以很好的学习其中的知识。
- 将英文翻译为中文,可以帮助其他一些英语阅读有困难的人来学习文中的知识(当然了,我现在能力有限,翻译的东西都是很简单的,但我希望以后能翻译一些很好的文中)
创建一个View类
一个设计良好的自定义View就像其它任何精心设计的类一样。它封装了一组特定的功能,并且有一个容易使用的界面,它还能有效地使用CPU和内存等等。尽管如此,除了是一个设计精心的类之外,一个自定义的view还应该
- 符合Android标准
- 提供可以在Android XML布局中使用的自定义属性
- 发送可访问的事件(这个翻译得不是很好,纠结中。。。)
- 能够兼容多个Android平台
Android框架提供了一组基类和XML 标签来帮助你创建一个可以满足所有这些要求的自定义view。这节课讨论的如何使用Android框架来创建一个自定义view的核心功能。
继承一个View
Android框架中定义的所有视图类都是继承View类的。你的自定义view也可以直接的继承View类,或者你可以通过继承一个已经存在的View的子类比如Button类来节省时间。为了允许Android Developer Tools 与你的view相互配合,你至少提供一个含有一个Context对象和一个AttributeSet对象为参数的构造方法。这个构造方法允许布局编辑器来创建和编辑一个你的视图的实例。
class PieChart extends View {
public PieChart(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
定义自定义属性
为了添加一个内置的View到你的用户界面,你要指定一个XML元素和控制其外貌和行为的元素属性。精心编写的自定义视图也可以通过xml来添加和设置样式。为了让你的自定义视图能够有这个效果,你必须做到:
- 在一个<declare-styleable>资源元素中为你的视图自定义属性
- 在xml布局中制定属性的值
- 在运行的时候获取属性的值
- 使用获取到的属性值
这一节将讨论如何定义属性和为它们指定属性值。下一节将说明在运行的时候处获取和应用这些属性值。
要定义自定义的属性,需要添加
<declare-styleable>资源到你的项目中。习惯性的将这些<declare-styleable>资源放到一个
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>
以上代码声明了两个自定义属性,即 showText 和 labelPosition,这两个属性都属于一个名叫PieChart的styleable 实体。按照惯例,这个styleable实体的名字应和自定义view类的类名一样。尽管这不是严格要求你必须要遵循这个惯例,但是许多流行的代买编辑器都依靠这种命名约定来提供代码提示。
一旦你自定义的属性,你就可以像内置的属性一样在xml 文件中使用它们。唯一区别是你自定义的属性属于一个不同的命名空间。它们不是属于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>
为了避免必须使用很长的命名空间URI,这个例子中使用了一个 xmlns 的指示符,这个指示符分配了一个别名 custom给命名空间 http://schemas.android.com/apk/res/com.example.customviews ,你可以为你的命名空间取任意的别名。
注意将自定义view添加到layout布局中的xml 标签的名字,它是完全限定自定义view类的名字的。如果你的view类是一个内部类,你需要通过视图的外部类的名字来进一步限定。进一步,例如,这个
PieChart 类有一个内部类
PieView,为了使用自定义属性,你应该使用标签
com.example.customviews.charting.PieChart$PieView
。
应用自定义的属性
当一个视图由一个XML布局创建的时候,XML标签中的所有属性都从资源束中读取,并且作为一个
AttributeSet对象
传递到视图类的构造方法中。虽然可以直接从AttributeSet对象中读取value值,但是那样做有一些缺点:
- 属性值的资源引用还没有解决
- 样式没有被应用
可以将
AttributeSet
传递给 obtainStyledAttributes()
来代替,这个方法返回一个已经被引用和添加样式的 TypedArray
数组值。
Android资源编译器为你做了许多事情来让你更容易的调用 obtainStyledAttributes() 。对于每一个<declare-styleable>资源,在R.java文件中产生了定义了一组属性id和一组定义了数组中每个元素索引的常量。你用预先定义好的常量来从
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
对象是一个共享的资源,用完之后要回收(recycle)
添加属性和事件
属性是一种很有力的控制view的行为和界面的方法,但是它们只能在view初始化时被读取。为了提供动态的行为,需要显示的提供每一个自定义属性的getter 和 setter方法。下面的代码片段展示了
PieChart如何暴露
showText的属性:
public boolean isShowText() {
return mShowText;
}
public void setShowText(boolean showText) {
mShowText = showText;
invalidate();
requestLayout();
}
自定义view也应该支持事件监听来传达重要的事件。例如,PieChart提供了一个叫
OnCurrentItemChanged的
自定义的事件来通知监听者用户已经旋转了饼图从而专注于新的饼图。
很容易忘记提供属性和事件,特别是当你只是使用自定义view时。请花一些时间来仔细的定义你的接口来减少以后维护的开销。一个好的可以遵循的规则是总是提供可以影响自定义视图的形状或者行为的特性。
为体验设计
你自定义的view应该可以支持大范围的用户,这些用户包括那些看不见或者无法触摸的残疾人。为了支持这些残疾用户,你应该:
- 用android:contentDescription 属性标注你的输入框
- 在适当的时候通过调用
sendAccessibilityEvent()
方法来发送可访问的事件 - 支持备用控制器,比如 D-pad 和 trackball
更多关于创建可访问的视图的信息,你查阅Android Developer Guide中的
Making Applications Accessible