基于两个基础的类:View和ViewGroup,Android提供了一个精致而强大的组件化的用户界面。此前,Android平台预先提供了各种各样的View和ViewGroup的子类——被称作widgets和layouts。当然你也可以单独的构建你自己的ui。
可用的widgets包括 Button
, TextView
, EditText
, ListView
,CheckBox
, RadioButton
, Gallery
, Spinner
,还有基于特殊用途的AutoCompleteTextView
, ImageSwitcher
, and TextSwitcher
.
可用的layouts有 LinearLayout
, FrameLayout
, RelativeLayout
, 等,更多例子请查看 Common Layout Objects.
如果系统预先提供的widgets和layouts不能满足你的需求,你可以创建你自己的View子类。如果你想对系统提供的widgets和layouts做修改,你可以继承它们并重载它们的方法。
如果创建自定义的View的子类,你可以精确的控制它的外观和功能。下面是你能对自定义控件做的控制:
1 你可以创建一个完全自定义渲染方式的控件,例如一个用2d图形渲染的把手,类似于模拟电子控制。
2你可以将多个view组合在一起,成为一个单独的组件。
3你可以重载EditText在屏幕上的渲染方式(Notepad Tutorial 通过这个方式来达到好的效果)
4你可以捕捉其他的事件,并用自定义的方式处理他们。
下面的部分解释如何创造自定义控件,并在app中使用他们:
The Basic Approach
这里是在创建自定义控件之前你需要知道的一个概述:
1用你自己的类继承一个现存的View或其子类。
2重载一些父类中的方法。父类中以on开头的方法如:
,
onDraw()
,
onMeasure()
, and
onKeyDown()
.这和 Activity
or ListActivity
中的你复写on开头的方法一样。
3使用你自己的类,一旦上述步骤完成,你自定义的类就可以替代它所继承的View来使用。
tip:自定义的类可以作为要使用它们的Activity的内部类。这这很有用,因为控制了对他们的不必要的访问(当然你也许想创建一个新的公共类来在你的app中更广泛的应用)。
Fully Customized Components
完全自定义可以用来创建你所希望的以任何方式表现的绘图组件。无论什么方式,这是你用组合的控件怎么也做不到的。幸运的是,你可以创建具有任意外观和行为的控件,唯一的限制可能是你的想象力,屏幕的尺寸,处理器运算能力。
为了创建一个完全自定义的控件:
1继承最多的父类是View,所以你将经常从这里开始。
2可以增加一个构造器,它可以从xml文件中获取属性和参数,定义你自己的属性和参数(也许是颜色和宽度)
3可以在自定义的控件中创建你自己的事件监听器,属性访问器和修改器,和更复杂的行为
4重载onMeasure()方法。也很可能重载onDraw()方法,如果你要让控件显示什么的话。这两个函数都有默认的行为,onDraw()默认是什么都不做,onMeasure()方法将会设置100*100的尺寸(也许不是你要的)。
5根据需要重载其他on开头的方法
Extend onDraw()
and onMeasure()
onDraw()方法传递一个
Canvas类 ,通过它你可以实现任何图形:2d图形,其他的标准或自定义的控件,文字字体等
注意:这不能表现3d图形,如果你想使用3d图形,你必须继承SurfaceView而不是View,并另一个线程中绘制。在GLSurfaceViewActivity sample中获取更多信息
onMeasure()会被更多的调用。onMeasure()是组件和容器之间渲染关系的重要部分。onMeasure()必须高效而精确的重写,以此反应组件的把尺寸。这稍微有点复杂,它是通过父类的限制要求(其传递给onMeasure()方法)和用测量的宽度和高度(一旦计算完成后)调用setMeasuredDimension()方法的要求。如果你在重载的onMeasure()方法中调用setMeasureDimension()方法失败,结果将是一个在测量时的异常。
实现onMeasure()方法,大概步骤如下:
1重载的onMeasure()方法的参数有宽度和高度的测量规格(分别是widthMeasureSpec和heightMeasureSpec参数,两个都是整数来代表维度),这两个参数是你测量产生的高度和宽度的限制性要求。更详细的关于测量的说明可以在View的onMeasure()方法说明中找到。
2你的控件的onMeasure方法应该计算它自身的高度和宽度,这将被用来渲染这个控件。测量的大小应该尽量在传进来的规格参数之内,当然你也可以选择超过规格要求(在这种情况下,父容器可以选择怎么做,包括抛出异常,滑动,剪掉或者要求onMeasure用不同的规格再次测量)。
3一旦高度和宽度被测量,setMeasureDimension(int width,int height)方法必须被调用(将测量的宽和高作为参数传进去)。若失败的话将会抛出异常。
、
下面是一些框架会调用的view的标准方法的总结:
Category |
Methods |
Description |
Creation |
Constructors |
There is a form of the constructor that are called when the view is created from code and a form that is called when the view is inflated from a layout file. The second form should parse and apply any attributes defined in the layout file. |
onFinishInflate()
|
Called after a view and all of its children has been inflated from XML. |
Layout |
onMeasure(int, int)
|
Called to determine the size requirements for this view and all of its children. |
onLayout(boolean, int, int, int, int)
|
Called when this view should assign a size and position to all of its children. |
onSizeChanged(int, int, int, int)
|
Called when the size of this view has changed. |
Drawing |
onDraw(Canvas)
|
Called when the view should render its content. |
Event processing |
onKeyDown(int, KeyEvent)
|
Called when a new key event occurs. |
onKeyUp(int, KeyEvent)
|
Called when a key up event occurs. |
onTrackballEvent(MotionEvent)
|
Called when a trackball motion event occurs. |
onTouchEvent(MotionEvent)
|
Called when a touch screen motion event occurs. |
Focus |
onFocusChanged(boolean, int, Rect)
|
Called when the view gains or loses focus. |
onWindowFocusChanged(boolean)
|
Called when the window containing the view gains or loses focus. |
Attaching |
onAttachedToWindow()
|
Called when the view is attached to a window. |
onDetachedFromWindow()
|
Called when the view is detached from its window. |
onWindowVisibilityChanged(int)
|
Called when the visibility of the window containing the view has changed. |
A Custom View Example
自定义控件的一个例子,在api demos中有提供。自定义的view在LabelView中被定义。
LabelView的例子展示了自定义控件的许多方面:
1继承View类。
2参数化的构造器来加载参数(定义在xml)。其中一些传递给view的子类,但更重要的是,有一些自动义的属性定义在labelView中。
3你希望在label控件中出现的标准public方法,如setText(),setTextSize(),setTextColor()等
4重载的onMeasure方法来决定和设置控件的渲染范围(注意在LabelView方法中,真正的工作室由private的measureWidth()方法做的)
5重载的onDraw方法来把文字写在提供的canvas上
你可以在一些例子中的custom_view_1.xml看到LabelView的使用。特别的,你可以看到android:开头的参数和自定义的app:开头的参数的混合使用。app:开头的参数是LabelView中的,它们是在R资源定义类的内部类styleable类中定义的。