《Android Dev Guide》系列教程17:建立自定义组件

懒骨头(http://blog.csdn.com/iamlazybone)

Android 提供了一个成熟强大的组件模型来建立你自己的UI,他们都基于View和ViewGroup类。首先,平台包含了大量的已经定义好的子类,他们被称之为widgets和layouts,你可以用他们来构建你的用户界面。

包括Button、TextView、EditText、ListView、CheckBox、RadioButton、Gallery、Spinner和一些特别的,比如AutoCompleteTextView、ImageSwitcher、TextSwitcher。

布局包括LinearLayout、FrameLayout、RelativeLayout等等。

如果这些提前定义好的组件也不能满足你的需求,你可以定义自己的View子类。如果你只需要在已有的view子类基础上做很小的调整,那么直接继承,然后覆盖相关方法即可。

建立自己的view子类需要精确控制界面元素。可以参考以下几点:

@ 你可以建立一个完全自定义的渲染类型,也就是界面完全自己来画,例如使用2D图形渲染来绘制音量控制旋钮。

@ 你可以合并已有的view为一个新视图,例如ComboBox就是一个列表和按钮的组合,双窗格选择控件就是两个列表的组合(类似于省市联动吧,选了左边的省之后右边列表随之改动)。

@ 你可以重写EditText的显示部分,Notepad Tutorial就是一个很好的例子。

@ 你可以截获一些事件比如按键事件,比如可以用在游戏中。

下面的例子解释了怎样自定义view的建立和使用。

建立自定义View基本方式

下面是需要了解的几点:

1-继承View类

2-覆盖一些方法,例如一些on开头的方法,onDraw()、onMeasure()、onKeyDown()。

3-使用你自定义的类。一旦完成,新的view类就可以代替父类来使用了。

注意:自定义的View 可以当做内部类来使用。这样并不是必须的,但是这样可以控制自定义类被错误的访问。

建立完全的自定义的View

完全自定义的Vew可以建立你想要的任意的图形组件。可能是一个图形UV表、或者一个老的模拟计、或者一个长文本,如果一个弹跳球向前前进的话,你就可以唱卡拉OK了。(老外的幽了个默)

方法:

1-大多数的View你都可以继承,你通常会继承View类来建立自己的视图组件。

2-你可以提供构造函数来接收一些xml中定义的属性或者参数,后者自定义的。

3-你可以建立自己的事件监听器,属性访问器和属性修改器,这样做可能会显得更加复杂。

4-如果你想修改veiw来显示你的一些东西,你会希望重写onMeasure()方法,或者需要重写onDraw()方法。他们都有默认的行为,onMeasure()会默认设置100X100的一个大小,onDraw()默认什么也不绘制。

5-别的On方法或许也需要被重写。

继承onDraw()方法和onMeasure()方法

onDraw()方法会传递给你一个Canvas参数你可以在上面绘制2D图形或者自定义的组件、文本、或者其他你想绘制的。

注意:他不接受3D图形。如果你想绘制3D图形,需要继承SurfaceView类来代替View,并且需要在一个单独的线程绘制。可以参考GLSurfaceViewActivity这个例子了解详细情况。

onMeasure()方法会介绍的多一些。onMeasure()方法是当前部件和他的父部件之间的一个重要联系。onMeasure()方法必须被有效地重写,并且要精准的报告所含子组件的大小,这是由android这种较为严格的向父组件报告自己状态的要求来决定的,当部件的宽高需要被计算时,使用测量得到的宽度高度值来调用setMeasureDimension()方法传值?。如果重写了onMeasure()方法但你却每调用,那么计算宽高值时会出现异常。

你可以这样实现onMeasure()方法:

@ 被覆盖的onMeasure()应该给出边界值,(widthMeasureSpec和heightMeasureSpec参数都是int型的尺寸)。

@ 你所重写组件的onMeasure()方法应该计算宽高值因为在绘制组件时那两个参数是必须的。最好能保留传入参数的值,尽管可以把传入的值改大一些。在这种修改的情况下,组件的父组件会选择怎样处理:扔出异常或再次调用onMeasure(),最有可能的是保留原来的数值。

@ 一旦宽高被计算,setMeasuredDimension()方法一定会被调用,不然将会抛出异常。

一个自定义View的例子

在API Demos里有个自定义View的例子。是一个叫LabelView的例子。

LabelView例子演示了一些自定义View时需呀注意的地方:

@ 继承View类来完全的自定义组件。

@ 参数化的构造函数可以来接收传入的参数,参数在xml里定义。其中一些参数被传递到View父类里。但是更多的是自定义的属性值并且被LabelView所使用。

@ 一些标准的公共方法你可以参考Label组件,比如setText()、setTextSize()、setTextColor()等等。

@ 重写的onMeasure()方法定义了所要绘制组件的大小。注意一下在LabelView中,真正起作用的是measureWidth()方法。

@ 重写onDraw()方法是将组件绘制到给出的canvas上。

你可以参考custom_view_1.xml这个自定义label的例子。特别是,你可以看一下android:参数和app:参数之间的组合使用。app:参数是自定义的参数,在R资源文件里定义。

组合控件

如果你不想建立完全自定义的控件,而想使用现有的组件重新组合,这时便可以使用组合组件。概括的说,组合控件就是一些单一功能控件的组合。例如,一个组合框可以想象成一个文本输入框、一个按钮和弹出列表的组合。如果你按下按钮选择菜单,他将会弹出一个输入框,选择其中一项后,输入框机会被填充,当然了,用户也可以直接在文本编辑框输入内容如果他们愿意的话。

在Android里,有两个控件已经是组合控件了,Spinner和AutoCompleteTextView,但无论怎样,组合框的例子更容易被理解。

我们可以这样建立一个组合控件:

1-通常开始的时候需要建立一种布局,所以建立一个集成字layout的子类。可能我们需要使用LinearLayout不觉并且使用水平布局。记住布局之间可以嵌套,所以组合控件可以被设计成任何复杂的布局。注意,组合控件的布局文件可以在xml配置,也可以完全用代码来写。

2-在新类的构造方法里,首先要将参数传递给父类。然后再进行其他的设置。你可以在这里添加文本输入框和弹出列表,注意,你可以使用xml配置文件里的一些属性和参数。

3-你可以建立事件监听器,例如监听列表项是否被选择,或者文本编辑框的内容是否改变。

4-你可以重写on方法,例如onKeyDown()里,设置某个键被按下时显示下拉菜单。

总之,使用组合控件要注意一下几条建议:

@ 布局可以从xml读取或者用代码建立。

@ onDraw()和onMeasure()方法基本上都会正确的运行,一半不需要重写。

@ 最后,你可以快速的构建任意复杂的组合控件,然后像普通的控件那样来使用它。

组合控件的例子

在API Demos里有两个列表的例子,Example4 和 6展示了一个继承LinearLayout的组合控件的例子。

修改已存在的视图类型

还有种更见简单的创建自定义View的方法,就是改写已存在的视图类。如果已经有一个控件和你的需求十分接近,你只需要继承它并且重写你想改变的方法即可。在完全自定义的View类中你需要做所有的处理,但如果继承自一个已存在的view,那么很多事情不需要我们处理。例如,SDK里包含了一个NotePad 程序的例子。这个例子包含了很多android系统的很多方面的知识,包扩一个继承自EditView的文本编辑器。这不是一个完美的例子,而且APIs在不同版本可能会有所改变,但它展示了一些基本的东西。

你可以吧NotePad例子导入到Eclipse里,特别看一下MyEditText。java的定义。

下面是一些关键的地方:

1-定义:

MyEditText类是这样定义的:public static class MyEditText extends EditText。

它被定义为一个内部类,但却是public的,所以可以被别的类访问。

他是静态的,所以不允许通过“合成方法”来访问父类的数据,正因为这样,它是一个独立的和NoteEditer类无关的类。这是一种建立内部类的非常好的方法,如果它不需要从外部类访问状态,并且保证了外部类的精简,而且会更容易的被访问。

他继承自EditText,当我们完成子类时,子类就可以像一个EditText类那样被正常的访问了。

2-类的初始化

首先调用父类方法,此外,他是一个带参数的构造方法而不是默认的。通过使用xml读取的参数来创建EdieText类,在构造方法里还需要将这些参数传递给父类。

3-重写某些方法

在这个例子中,只有onDraw()方法被重写。

在重写onDraw()方法里,我们在canvas上绘制蓝色的线,canvas是onDraw()传进来的参数。父类的onDraw()在方法结束前被调用。父类的方法应该被调用,但此时我们最后再调用父类地方法,这样可以包含我们绘制的蓝色的线。

4-使用自定义组件

自定义组件写好之后,怎样用呢,以NotePad为例,可以直接在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" />

自定义的组件和通常的view一样,使用它们时需要使用整个包名,另外注意我们定义的内部类,要使用在java编程语言中的标准的引用内部类的方式:NoteEditor$MyEditText。

如果你没有定义成一个内部类,那么你可以使用xml元素名来声明view组件,例如:

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

注意:MyEditText类是一个独立的类文件,当它嵌套在NoteEditor 里是无效的。

就这些,虽然上面只是一个很小的例子,但建立自定义组件就需要了解这么多。
你还可以添加重写很多的方法和功能,唯一限制你的就是自己的想象力。

更多相关文章

  1. Android实现类似excel表格的方法整理
  2. 【Android性能优化】使用NDK进行Java和C++混编
  3. 一文彻底搞懂Android(安卓)View的绘制流程
  4. Android(安卓)Audio底层原理(一)
  5. Android研究院之应用程序ListView 详解 (六)
  6. 剖析 Android(安卓)架构组件之 ViewModel
  7. AIDL跨进程通信和Service调用
  8. Android(安卓)ContentProvider 使用
  9. Android(安卓)TV框架TIF

随机推荐

  1. Android加载大图Bitmap发生OOM(Out Of Mem
  2. Android笔记-2
  3. Android中利用GridView实现水平和垂直均
  4. Android(安卓)修改横屏角度为顺时针270度
  5. Android启动流程分析(十) action的执行和
  6. 【Android】注解框架(三)-- 编译时注解,手写
  7. [Android]Android(安卓)Studio获取开发版
  8. android:shape的使用
  9. Android的源代码结构
  10. Android是什么