解读创建自定义组件
自定义组件Android系统为用户创建自己的UI提供了功能强大的组件模型,这个模型是基于View和ViewGroup这些基本的布局类。Android系统包含了预先制作好的View和ViewGroup的子类————分别是widgets(窗口部件)和layouts(布局)————你可以使用这些已经提供的子类构建自己的UI,在刚开始接触Android开发时,我们都是使用这些系统提供的,然而,随着项目需要,这些基本的UI组件已经不能满足我们的需要了,这个时候就需要我们遵循组件模型来创建自定义UI组件。
widgets(窗口部件)主要包含了如下部分:Button、TextView、EditView、ListView、CheckBox、RadioButton、Gallery、Spinner,当然,也包括一些具有特殊用途的widgets:AutoCompleteTextView、ImageSwitcher和TextSwitcher。
layouts(布局)主要包含了:LinearLayout、FrameLayout、RelativeLayout和其他的。更多的示例,请看Common Layout Objects。
当已经存在的组件不能满足需求,我们就需要创建自己的View子类。如果,你仅仅是需要对存在的widget或layout进行一些小的调整,你可以简单的创建该widget或layout的子类并且覆盖其中的方法。
通过创建自己的View子类可以使自己精确的控制屏幕上每个元素的显示和其功能。这里列出了一些示例,给出了如何控制自定义组件的思路:
*你可以创建一个完全自定义渲染的View类型,例如:使用2D图形渲染“音量控制”旋钮,使其看起来像是一个模拟电量控制。
*你可以将一组View组件结合起来形成一个新的单个的组件,可能是使其像一个ComboBox(是由popup list和一个没有任何条目的text组合而成),一个dual-pane选择控制器(左右各有一个面板,并且每个面板中都有一个list,你可以通过指定一个pane中的内容使另一个pane随之改变,说了这么多,其实就是大家经常使用的天气预报中第一个下拉框中选择省份,随之第二个下拉框会随之变为该省份中包含的城市,这下懂了吧,呵呵!)等等示例。
*你可以覆盖EditeText组件在屏幕上渲染的方式(NotePad Tutorial使用这个方法创建一个lined-notepad页面)。
*你可以捕获其他一些事件,例如按键并且通过自定义的方式处理这些事件(例如在一个游戏中)。
下面的内容解释了如何创建自定义的Views并且在应用程序中使用这个自定义组件。对于详尽的参考信息,请看View类。
基本的方法
站在一个较高的层次上来看,要创建一个自定义的View组件,那么你必须知道如下内容:
1、让自己的类继承自存在的View类或者是View的子类。
2、覆盖超类的一些方法。要覆盖的超类的方法都是以”on“开头的,例如:onDraw()、ONMeasure()和onKeyDown()。这有点类似于Acitivity或ListActivity的on...事件,你为它们的生命周期和完成其他的功能而覆盖这些方法(on...事件).
3、使用你自己新建的扩展类。一旦完成,你可以在能够使用基类的地方使用自定义的这个扩展类。
提示:扩展类可以作为内部类在要使用这个扩展类的activities中定义。这一点不是必须的,但是却是非常有用的,因为它控制对扩展类的使用权限。
完全自定义的组件
完全自定义的组件可以用来创建图形组件在任何你想要显示的地方显示。可能是一个看起来像老式模拟计的图形VU计,或者是一个带有前进的球的长文本框,球随着字符移动,使得你可以用一台卡拉OK机唱歌。还有,你需要做一些事情,可是无论怎么组合现有的组件都无法达到想要的效果(这个时候就需要完全自定义的组件)。
幸运地是,你可以很容易创建出样式和功能都符合自己需求的组件,限制的因素仅仅是你的想象力、屏幕的尺寸和可用的电量(必须记住,你的应用程序通常都是在比桌面环境电量低得多的设备上运行)。
创建一个完全自定义的组件:
1、毫无疑问,最常继承的就是View。因此,你通常是继承这个类来实现自定义组建的;
2、你可以提供一个构造器来从XML文件中获取和解析属性及其参数,并且你可以自定义属性及参数(可能是VU表的颜色和取值范围或者是面条的宽度等等);
3、你可能希望创建自己的事件易做图,属性的accessors(获取器)和modifiers(修改器)或者是其他更复杂的动作。
4、如果你希望通过自定义组件显示一些事物,那么你几乎总是需要覆盖onMeasure()并且经常需要覆盖onDraw()。以上两者都包含默认的动作,onDraw()的默认动作是不执行任何操作,onMeasure()的默认动作是设置显示尺寸是100X100————而这个默认尺寸可能并不是你所想要的(尺寸)。
5、其他的on...的方法在需要的时候也必须覆盖。
扩展onDraw()和onMeasure()
onDraw()方法传递一个Canvas给你,你可以在这个Canvas上面完成自己想要的效果:2D图形、其他标准的或自定义的组件、styled text、或者其他任何你想要的事物。
注意:这个并不能用来完成3D图形。如果你想使用3D图形,那么你必须扩展Su易做图ceView来取代View,并且在一个独立的进程中完成绘制。对于细节部分可以查看GLSu易做图ceViewActivity示例。
onMeasure()要涉及得更多一点,onMeasure()是自定义组件和包含它的容器间的rendering contract非常严格的一个部分。onMeasure()必须被覆盖来非常高效和准确的报告它所包含部分的尺寸。来自父组件(传递进onMeasure方法的部分)的限制和通过测量的尺寸来调用setMeasureDimension()方法都将会使得这变得有一点点复杂。如果你从一个覆盖的onMeasure()方法中调用这个方法(setMeasureDimension())失败,那么在测量的时候将会引起异常。
站在一个较高的层次来看,实现onMeasure()就如同下面这样:
1、覆盖的onMeasure()方法是随着宽度和高度测量规范(widthMeasureSpec和heightMeasureSpec参数,都是代表尺寸的整型数)来调用的。对于这些规范可以获取的限制种类的完整参考可以在View.onMeasure(int, int)这个文档中找到(这个参考文档对完整的测量操作作出了比较好的解释)。
2、你自定义组件的onMeasure()方法必须计算出一个宽度和高度值,这两个值是用来渲染组件用来。这两个值必须处于传递进去的测量规范之内,尽管它可以选择扩展它们(宽度和高度这两个值)(在这种情况下,父组件可以选择如何处理:包括可以翻转、滚动、抛出一场或者是让onMeasure()以不同的测量规范重试)。
3、一旦宽度和高度计算好了之后,必须用得到的这两个计算值作为参数来调用setMeasureDimension(int width, int height)方法。如果这个操作失败了,那么将会引起抛出异常。
下面是对应用程序框架将会在views上面调用的标准方法的一个总结,如下图:
一个自定义View的例子
在API Demos子中提供的 Custom View例子是解释创建自定义View的很好的例子。Custom View例子中自定义的View是定义再LabelView这个类中的。
LabelView展示了一个自定义组件很多不同的方面:
*通过扩展View类来创建一个完全自定义的组件;
*参数化的构造器,使得可以解析参数(参数定义在XML文件中)。参数中的一部分是要传递给View这个基类的,但是更重要的,这个例子里还为LabelView这个组件定义了一些自定义属性。
*使用了label这个组件类型的标准公共方法,例如:setText()、setTextSize()、setTextColor()等等。
*使用了覆盖的onDraw()方法,将这个label画在提供的canvas上。
你可以在custom_view_1.xml这个文件中看到LabelView的一些示例用法。特别的是,你将会看到混合使用了android:namespace参数和自定义的app:namespace参数。LabelView可以识别这些app:参数,并工作良好,这些参数都定义在示例的R资源定义类的一个styleable内部类中。
<!-- Demonstrates defining custom views in a layout file. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.android.apis"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.example.android.apis.view.LabelView
android:background="@drawable/red"
android:layout_width="match_parent"
android:layout_height="wrap_content"
&nbs
补充:移动开发 , Android ,