Android 自定义View教程(一)

创建一个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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值