Android 自定义View教程(一)

来源:互联网 发布:金山数据恢复手机版 编辑:程序博客网 时间:2024/04/30 13:23

创建一个View类

一个设计良好的自定义view和其他任何设计良好的类一样。对于一系列的特定功能进行封装,提供简单易用的接口,还需要更有效率地使用CPU与内存。为了成为一个设计良好的类,一个自定义View需要做到以下几点:

  • 符合Android的标准

  • 使用Android XML Layouts 提供自定义的属性

  • 发送可接受的事件

  • 在Android多版本具有兼容性

Android框架层提供了很多基类以及XML标签来帮助你应对创建View时所需要的东西。这篇教程将讨论如何使用Android的框架来创建View的核心功能。

继承一个View

在Android框架层定义的所有的View类都继承自View。你的自定义View同样继承自View。你也可以通过继承一些已经存在的View子类来节省时间,举个例子:Button。

为了能够允许Android Developer Tools来和你的View交互,你至少需要提供一个带Context,AttributeSet参数的构造器。这个构造器允许Layout编辑器创建以及编辑你的View。

class PieChart extends View {    public PieChart(Context context, AttributeSet attrs) {        super(context, attrs);    }}

定义自定义的属性值

为了能够使用你的View,你需要在XML元素中指明属性并用它来控制View的外表以及行为。一个已经写得很好的View同样可以通过这样方法来添加和定义属性。为了能让你的自定义View做到以上所说:

  • 用<declare-styleable>资源标签来定义你自定义View的属性
  • 在你的Layout中指明属性的值
  • 在运行时检索到属性值
  • 将检索到的值应用到你的View中

这部分讨论了如何去定义自定义的属性值并且指明它的值。下一部分解决在运行时检索和应用这些值。

为了定义自定义属性值,添加<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 实体里。这一实体的名字按照惯例是与你的自定义View一样的,即使不是必须严格遵守这条惯例,但是很多流行的代码编辑器都依赖于这个命名惯例来提供状态实现。

一旦你定义了自定义的属性值你就能够在Layout 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>

为了避免不得不重复the long namespace URI 使用了xmlns指令这个指令分配了别名:custom 给命名空间http://schemas.android.com/apk/res/com.example.customviews。你可以选择任何你想的别名给你自己的命名空间。

注意到这个给你的自定义View添加的XML标签的名字。这是一个完整的自定义类的名字。假如你的View类是一个自带的内部类,你必须进一步完整写出它的外部类的名字。接下来,对于实例,PieChart 类具有一个内部类叫做PieView。使用这个类的自定义属性,你需要这么来使用:com.example.customviews.charting.PieChart$PieView。

应用你的自定义属性

当一个View在一个XML layout文件中被创建时,所有在XML标签中的属性都将会被从资源bundle中读取到view的构造器中,其载体为:AttributeSet。即使现在能够立即从AttributeSet中取出值,但是这么做有以下一些缺点:

  • 属性值还没有被解引用
  • Styles还没有被应用

取而代之的做法是,使用obtainStyledAttributes()来处理AttributeSet。这个方法将会返回一个TypedArray,里面有一个已经解引用且应用了Style的一组属性值。

Android资源编译器已经在你调用obtainStyledAttributes()的时候帮你做了很多工作。对于每一个在资源池中的<declare-styleable>资源,在生成的R文件中同时定义了属性数组的id值和在数组中的index值。你需要使用来自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();   }}

需要注意的是TypeArray对象一个可被共享的资源,需要在使用之后进行回收。

添加内容和事件

属性值是一个很强大的工具,主要是用来控制Views的行为以及外观,但是它只能在View初始化完毕后进行读取。为了提供动态的特性,暴露View每一个属性值的内容的getter/setter。以下的代码展示了PieChart如何暴露名叫showText的内容:

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

注意到setShowText中调用了invalidate() 以及 requestLayout()。这些调用对于确保View行为的可靠性是具有决定性作用的。你必须在View的内容发生变化且可能改变它的外观的时候,使用invalidate(),这样的话,系统就能够知道它需要被重绘。同样的,你需要在内容变化且影响到了View的大小的请求一个新的Layout。忘记这些调用会带来的“很难被发现的” bugs吧。

自定义View也需要支持事件监听器来与重要的事件进行交流。具体来说,PieChart 暴露了一个自定义的事件叫做:OnCurrentItemChanged 用来唤醒监听器,这样的话,用户就能够旋转应用。

忘记暴露内容与事件是很容易发生的,尤其是在当你是这个自定义View的唯一使用者的时候。多花一些时间来关心一下你的View的接口定义,这样可以减少未来的维护成本。有一条非常好的规则:那就是对于你的自定义View,总是暴露出任何影响外观可见性以及行为的内容。

0 0