前一篇讲的是组合已有的组件成为一个新的独立的组件,比较简单,今天研究了一下自定义组件的另外一种形式:对已有的组件进行修改(Modifying an Existing View Type),偷个懒,直接翻译一下Android 帮助文档。

    如果原生组件与我们想要的组件已经很相似了,此时可以简单地继承原生组件并只需要重写我们想要的方法使之符合我们的需求即可。当然这些可以通过完全自定义组件(直接继承自View进行绘制)来完成,但是如果你从组件的继承层次的某个组件开始的话,可以轻松得到很多需要的特性而不需要自己动手来实现。

    再SDK中有一个 NotePad application 的例子,这个例子中扩展自EditText,实现了一个有下划线的记事本。PS:特地找了一下,这个例子在Sdk/samples/android-19/legacy目录下。

    额,接下来帮助文档中就针对SDK中的这个例子进行了详细说明,拿我也原原本本的翻译吧。

1.定义

    自定义组件的类是这个样子地:public static class MyEditText extends EditText

。。它在NoteEditor中被定义为内部类,但是由于它是public的所以外部类可以通过NoteEditor.MyEditText来访问这个类

。。它是静态类,这意味着不会产生所谓的合成方法,可以访问基类中的数据,这也表示MyEditText是独立的类而不是依赖于NoteEditor。这是一种创建内部类的简洁的方法。

。。它继承自EditText,当我们完成这个组件的实现后就可以用它来代替EditText了

2.类的初始化

    首先调用super,而且这不是一个默认构造函数,而是带参数的构造函数。当从XML文件中inflateEditText时,这些参数用于创建组件,所以,我们的构造函数需要获得这些参数并将他们传给基类

3.重写的方法

    在这个例子中,只有一个方法需要重写:onDraw()。 重写这个方法允许我们在EditText的canvas上画上蓝线(canvas作为参数传给onDraw())。再我们重写的onDraw结束之前需要调用super.onDraw()。基类的方法应该被触发,但在这个例子中基类的方法在我们绘制完线后进行的调用。

4.自定义组件的使用

。。在这个例子中,我们直接在布局文件中使用自定义的组件,可以看一看noteEditor_editor.xml

<view
       class="com.android.notepad.NoteEditor$MyEditText" 
       id="@+id/note"
       android:layout_width="fill_parent"
       android:layout_height="fill_parent"
       android:background="@android:drawable/empty"
       android:padding="10dip"
       android:scrollbars="vertical"
       android:fadingEdge="vertical" />

。。再XML中自定义的组件像通用组件一样创建,而且使用包的全名来指定的。值得注意的是我们定义的内部类仍然使用NoteEditor¥MyEditText来引用,这是java中访问内部类的标准方式。如果我们自定义的组件不是内部类,我们可以在XML中这样来使用:

<com.android.notepad.MyEditText
  id="@+id/note"
  ... />

而不必使用“class”属性。

。。传递给自定义组件的构造函数的是另外的一些属性和参数,他们随后被传递给基类EditText的构造函数,这时我们的组件与基类EditText使用的是一样的参数。注意,可以添加其他的参数,我们将在下面进行说明。

    这是一个简单的例子,重点是:creating custom components is only as complicated as youneed it to be.