Android 用户界面---定制组件(Custom Components)(二)

长平狐 发布于 2012/10/16 10:18
阅读 163
收藏 0

复合控件

如果不想创建一个完全定制的组件,而是想要把一组既存的控件放到一起,形成一个可重用的组件,那么创建一个复合组件(或复合控件)是一个合适的选择。在一个容器中,复合组件把多个原子化的控件(或View)组合成一个逻辑组,它能够处置一件单一的事情。例如,ComboBox控件,就是通过一个单行文本域、一个按钮和一个弹出列表组合而成的,如果按下按钮并且从列表中选择了一项,那么选择项就会填入单行文本域,而且如果用户喜欢,也可以直接把内容输入到文本域中。

Android中,实际上有另外两View可以很容易的完成ComboBox的工作:SpinnerAutoCompleteTextView,但是不管怎样,使用ComboBox的例子会使得概念更容易理解。

以下是创建复合组件的步骤:

1.  通常的起点是用某种类型布局,创建一个扩展布局的类。在ComboBox的例子中,可以使用水平方向的LinearLayout布局。其他布局也可以嵌套到内部,以便复合组件能够随意的组合。注意,跟Activity一样,既可以使用基于XML声明的方法来创建一个复合组件,也可以编程的方式把它们嵌入到代码中。

2.  在新类的构造器中,可以带入任何子类需要的参数,并且首先要通过子类的构造器来传递它们。然后,就可以创建新组件中使用的其他的View了;ComboBox组件就是在这个时候创建了文本域和弹出列表。注意,也可以把自己的属性和参数引入到XML声明中,这些属性和参数能够被构造器使用。

3.  还可以给被包含的View所可能产生的事件创建监听器,例如,针对列表项的Click监听器的方法,如果一个列表项被选择了,那么这个监听器方法就会更新文本域的内容。

4.  创建自定义带有访问器和编辑器的属性,例如,ComboBox组件中针对文本域的get…set…方法。

5.  在扩展一个Layout的情况下,不需要重写onDrawonMeasure()方法,因为布局的默认行为就可以很好的工作。但是,如果需要你依然可以重写它们。

6.  还可以重写其他的on…方法,如可以重写onKeyDown()方法,当某个键被按下时,可以从ComboBox的弹出列表中选择某些默认值。

总结,使用布局作为定制控件的基础有以下好处:

1.  能够像Activity一样使用声明的XML文件来指定布局,也能够用编程的方式创建View,并且从代码中把它们嵌入到布局中。

2.  onDraw()onMeasure()方法(还有其他的大多on…方法)都有适当的行为,因此不用重写它们。

3.  最后,可以快速的构造任务复杂的复合View,并且可以把它们作为一个单一的组件来重用。

复合控件的例子

SDKAPI Demos工程中,有两个List的例子---Views/Lists目录下示例4和示例6演示了一个SpeechView组件,它扩展了LineraLayout布局让组件显示语音查询结果。对应的类在List4.javaList6.java的示例代码中。

修改既存的View类型

在某些情况中,对于创建有用的定制的View甚至有更容易的选项。如果有一个既存的组件与想要的非常相似,就可以简单的扩展这个组件,并且重写想要改变的行为。可以用完全定制的组件做所有想做的事情,但是通过从View层次树中的一个更特殊的类开始,还能够获得更多的你所期望的已经实现的行为。

例如,在SDK包含的NotePad应用程序的示例中,有许多使用Android平台的特征,其中有扩展EditText控件的单行记事本。这不是一个完美的例子,但是它演示了组件定制的一些原则。

使用下面链接,把NotePad示例的代码导入到Eclipse中,实际看一下NoteEditor.java文件中LinedEditText类的定义。

http://developer.android.com/resources/samples/NotePad/index.html

需要注意的一些问题:

1.   定义

使用下面方法来定义类:

public static class LinedEditTextextends EditText

A. 它是作为NoteEditorActivity的一个内部类来定义的,但是它是公共的,这样如果需要,就可以在NoteEditor类的外部用NoteEditor.MyEditText方式来访问。

B. 它是静态的,这就;意味着不会产生所谓的允许访问来自父类的数据的合成方法,反过来意味着它实际是作为一个独立的类,而没有跟NoteEditor进行强制的关联。如果不需要从类的外部访问状态,要保持生成小的类,并且还要允许在其他类中能够容易的使用它,那么这是一种创建内部类的比较清晰的方式。

C. 它扩展了EditText类,它是我们选择的要定制的View。定制完成后,新的类可以替代普通的EditText类。

2.  类初始化

始终首先要调用的是super方法,它不是默认的构造器,而是参数化的一种方式。EditText是用XML布局文件中的这些参数来创建的,因此,我们的构造器需要带入这些参数,并把它们传递给父类的构造器。

3. 重写方法

这个例子中,仅重写了一个方法:onDraw().

对于NotePad示例,重写onDraw()方法允许我们在EditText的画布上画蓝线(画布是有重写的onDraw()方法传入的)。在这个方法的最后,调用了super.onDraw()方法。父类的方法应该被调用,但是在这个例子中,我们在画完我们想要的线之后调用了父类的onDraw()方法。

4.  使用定制组件

组件定制完之后,如何使用它呢?在NotePad例子中,定制组件在声明的布局中被直接使用,因此需要看一下res/layout文件中的note_editor.xml文件中的声明:

<view xmlns:android="http://schemas.android.com/apk/res/android"

    class="com.example.android.notepad.NoteEditor$LinedEditText"

    android:id="@+id/note"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:background="@android:color/transparent"

    android:padding="5dp"

    android:scrollbars="vertical"

    android:fadingEdge="vertical"

    android:gravity="top"

    android:textSize="22sp"

    android:capitalize="sentences" />

定制的组件是用XML中的一个一般的View来创建,并且使用完整的包名来指定类。还要注意定义中引用内部类的方法:NoteEditor$LinedEditText,这是Java编程语言标准的引用内部类的方法。如果定制View组件没有作为内部类来定义,那么就要选择用XML元素名来声明View组件,并且要去除类的属性,如:

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

注意,LinedEditText类是一个独立的类文件,当这个类被嵌套在NoteEditor类中时,这种技术是不会工作的。

定义中的其他属性和参数被传入定制组件的构造器中,然后传递给EditText类的构造器,因此这些属性和参数与EditText类使用的是相同的。注意,也可以添加自己的参数。


原文链接:http://blog.csdn.net/fireofstar/article/details/7428151
加载中
返回顶部
顶部