Android绘图机制(四)自定义控件

来源:互联网 发布:建模 软件 数据 开源 编辑:程序博客网 时间:2024/04/30 15:34

       概述 

       Android提供了一套复杂而强大的组件模板,让开发者基于基本的布局类View类和ViewGroup类来创建自定义控件。Android框架已经包含了各种各样的预设的View和VIewGroup子类,既基本控件和布局,开发者可以根据这些控件和布局开发独立的UI控件。

        部分基本控件包括Button,TextView,EditText, ListVIew, CheckBox,RadioButton,Gallery,Spinner等,以及具有特殊用途的AutoCompleteTextView,ImageSwitcher,和TextSwitcher等。基本布局类包括 LinearLayout, FrameLayout, RelativeLayout等,可以查看Common Layout Objects文档部分获取更多详情。 
        如果所有的这些预设控件都无法满足需求,那么开发者可以开发自己的View子类。如果你只需要在现有的基本控件上做一些较小的调整,你可以简单的继承现有的控件,并重写其中一些方法即可。

        通过创建自定义控件,可以严格控制屏幕元素的外观和内部方法。下面是一些关于开发自定义控件的建议:
       *你可以创建一个完全自定义渲染的视图类型,例如,一个通过2D图形绘制的模拟电子控制的音量控制键,
       *你可以将一组控件组合到一个独立的控件中,比如说创建一个类似ComboBox的控件(一个弹出列表和自由文本组合),或一个多重选择器面板(包含左右两个面板,每个面板包含一个列表,可以选择其中一个面板的内容添加到另一个面板中),等等。
       *你可以重写一个EditText控件在屏幕上的渲染方式(笔记本辅助工具应用这点创建了行内的页面,并具有很好的效果)
       *你可以通过自定义的方式获得一些其他的事件,例如点击事件,不过处理你自己的工作。
      下一节将会解释如何创建一个自定义控件,并将其运用到你自己的应用中,要获得更详细的参考信息,可以查看View类的相关指导。


       基本方法
      下面是在创建自定义控件过程中的一些基本的步骤
       1. 让你的自定义控件类继承View,或者View的子类。
       2. 重写父类的某些方法,通常是一些以on开头的方法,如onDraw(),onMeasure(),onKeyDown()。这一点与Activity或ListActivity中重写的生命周期方法和其他功能挂件方法类似。
       3. 应用你的自定义控件。自定义控件创建完成后,这些自定义控件就可以像他们的基类一样使用。
建议:自定义控件可以在他们被使用的地方作为内部类定义。这一点非常有用,因为你也许不需要在其他地方使用这些控件。


        完全自定义控件

        通过完全自定义的方式,可以创建在其他任何地方都可用的生动的控件。比如一个具有滚动球的单行文本视图,其中的滚动球可以根据你在KTV里唱歌时歌词的进度而滚动。或者说是任何预设控件不能完成的事,你都可以随意组合。


        创建完全自定义控件:
       1. 最常用于继承的是View类,所以通常可以继承该来来创建自己的超级自定义控件。
       2. 你可以提供一个构造函数,这个构造函数可以获取xml文件中的属性和参数(可以是自定义属性),并且你可以使用这些属性和参数(比如可以是颜色,和音量范围等)
       3. 也许你想要创建自己的事件监听器, 属性获取器和属性编辑器,或者更多复杂的行为。 
       4. 如果你想让自定义控件展示一些东西,那么你可能需要重写onMeasure()和onDraw()。不过,这两个方法都有默认的行为,onDraw()的默认行为是什么都不做,onMeasure()的默认行为通常是设置一个100*100的视图尺寸(可能这不是你想要的)


        继承onDraw()和onMeasure()

        onDraw方法传递一个画布,可以通过继承该方法实现你想要的效果,如绘制2d图形,或者其他标准化的自定义控价,样式化的文本,以及其他你能想到的效果。 

注意:继承onDraw和onMeasure无法应用3d绘图,如果你想要使用3d效果,你必须继承SurfaceView而不是View, 并在一个独立的线程内进行绘制,可以查看GLSurfaceViewActivity实例获取跟多详情(可以参考:http://blog.csdn.net/pku_android/article/details/7522459)。

         onMeasure()方法有点小复杂。该方法的内部实现是在组件和其父容器相互关联的过程中比较棘手的一个阶段。onMeasure()应该被有效而精确地重写以报告其内容部分的尺寸规格。来自父类的约束(这些约束会被传入onMeasure()中)和调用setMeasureDimension()方法获得的约束(包含测量后的宽度和高度)使得这个onMeasure()的过程变得更加复杂,如果你在复写的onMeasure()方法中处理测绘的过程失败,那么绘制是可能会发生异常。

        概括性地讲,实现onMeasure()方法类似于下面的过程:
        1.  包含宽度和高度约束作为参数的重写的onMeaure()方法会被调用(既参数值为widthMeasureSpec和heighMeasureSpec,这两个规范都是一个表示尺寸的整型值),这些测量规范应该是你将要生成的宽度和高度的尺寸的限制规范。这些规范的完全参考可以在参考文档的view.onMeasure(int, int)下查看,
        2.  自定义控件的onMeasure()方法应该计算出一个宽度和高度尺寸用于后期视图的渲染。这些尺寸规范在传入时应该被保持,尽管这些值可以被覆盖(在这种情况下,俯视图可以选择怎么处理,包括裁剪,滚动,抛出异常,或者是请求onMeasure()方法根据不同的尺寸规范重新测量)。
        3.  一旦宽度和高度被计算出来, 那么必须根据这些测量出来的值调用setMeasuredDimension(int width, int height)方法,处理失败则会抛出异常。


protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)

方法解释:测量视图和其内容,决定测量后的宽度和高度,这个方法会被measure(int,int)调用并应该被其子视图重写,以对其内容提供有效而精确的规则。
约定:重写这个方法时必须调用setMeasureDemension(int, int)保存测量后视图的宽度和高度。如果这个过程失败,则会触发异常,通过measure(int,int)抛出“calling the superclass onMeasure(int,int)是不合法的用法”。
子类默认测量的是背景的尺寸,除非父类提供的MeasureSpec允许更大的尺寸,子类应该重写onMeasure(int, int)以对其内容提供更好的尺寸规范。
如果重写了这个方法,那么子类会确保测量宽度和高度至少是视图的最小高度和最小宽度(getSuggestedMinimumHeight()和getSuggestedWidth())        


下面是框架会在视图上调用的其他一些标准化方法的概况:

CategoryMethodsDescriptionCreationConstructorsThere 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()当一个视图和他的所有的子视图从布局文件中被全部找出时调用LayoutonMeasure(int, int)调用这个方法,确定视图和其所有子视图的尺寸规范onLayout(boolean, int, int, int, int)当视图需要为其子视图设置一个尺寸或者放置一个位置时调用onSizeChanged(int, int, int, int)当视图的尺寸改变时调用DrawingonDraw(Canvas)当视图需要渲染其内容时调用Event processingonKeyDown(int, KeyEvent)大概一个新的按键事件发生时调用onKeyUp(int, KeyEvent)当一个按键事件抬起时都用onTrackballEvent(MotionEvent)当一个轨迹球事件发生时调用onTouchEvent(MotionEvent)当触屏事件发生时调用。FocusonFocusChanged(boolean, int, Rect)当视图获得或失去焦点时调用onWindowFocusChanged(boolean)当包含视图的窗口获得或失去焦点时调用AttachingonAttachedToWindow()当视图附着到窗口上时调用onDetachedFromWindow()当视图从窗口分离时调用onWindowVisibilityChanged(int)当包含该视图的窗口的可见性改变时调用

下一篇继续:)

protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
1 1