Android之自定义View(一)

    在界面上Android提供了一套GUI库,里面有很多我们常用的控件,但是很多时候我们并不满足于这些控件,因为这样意味着界面的同质化很严重,为了能做出与众不同的界面,我们就要创造自己的控件,也就是自定义View。自定义View是高级进阶的必经之路,学习自定义View之前,我们先要了解View的工作原理。

    ViewRoot和DecorView

   ViewRoot对应于ViewRootImpl类,它是连接WindowManager和DecorView的纽带,View的三大流程均是统统ViewRoot来完成的。在ActivityThread中,当Activity对象被创建完毕后,会将DecorView添加到Window中,同时会创建ViewRootImpl对象,并将ViewRootImpl对象和DecorView建立关联。

    View的绘制流程是从ViewRoot和performTraversals方法开始的,它经过measure、layout和draw三个过程才能最终将一个View绘制出来。measure过程决定了View的宽高,layout过程决定了View的四个顶点的坐标和实际View的宽高,draw过程决定了View的显示,只有draw方法完成以后内容才能显示在屏幕上。

    DecorView作为顶级的View,一般情况下内部会包含一个竖直的LinearLayout,在这个LinearLayout中包含上下两部分(具体跟Android版本及主题有关),上面是标题栏,下面是内容栏 。

Android之自定义View(一)_第1张图片        

        DecorView其实是一个FrameLayout,View层的所有事件都先见过DecorView,然后才传递给我们的View。

 理解MeasureSpec

        MeasureSpec在很大程度上决定一个View的尺寸规格。在测量过程中,系统会将View的LayoutParams根据父容器所施加的规则转换成对应的MeasureSpec,然后再根据这个MeasureSpec测量出View的宽高。MeasureSpec代表一个32位int值,高2位代表SpecMode,低30位代表SpecSize,SpecMode是指测量模式,而specSize是指在某种测量模式下的规格大小。

SPecMode有三类,每一类都表示特殊的含义,如下所示

UNSPECIFIED

父容器不对View有任何限制,要多大给多大,这种情况一般用于系统内部,表示一种测量的状态。

EXACTLY

父容器已经测量出View所需要的精确大小,这个时候View的最终大小就是SpecSize所指定的值。它对应于LayoutParams中的match_parent和具体的数值这两种模式。

AT_MOST

父容器指定了一个可用大小即SpecSize,View大小不能大于这个值,具体是什么值要看不同View的具体实现。它对应于LayoutParams中的Wrap_content

普通view的MeasureSpec的创建规则

Android之自定义View(一)_第2张图片


 View的工作流程

        View的工作流程只要是指measure、layout和draw三大过程,即测量、布局和绘制。其中measure确定View的测量宽高,layout却东View的最终宽高和四个顶点的位置,而draw则将View绘制到屏幕上。

 自定义View的分类

1、   继承View重写onDraw方法

    需要自己支持wrap_content,并且padding也要自己处理

2、继承ViewGroup派生特殊的Layout

    需要合适处理ViewGroup的测量、布局这两个过程,并同时处理子元素的测量和布局过程

3、继承特定的View(比如TextView)

    这种方法比较容易实现,不需要自己支持wrap_content和padding等

4、继承特定的ViewGroup(比如LinearLayout)

这种方法也比较常见,当某种效果像几种View组合在一起的时候,可以采用这种方法实现

自定义View的注意事项

1、让View支持wrap_content

    直接继承View或者ViewGroup的控件,如果不在onMeasure中对wrap_content做特殊处理,那么使用wrap_content时等于match_parent的效果,无法达到预期效果。

2、如果有必要,让你的View的padding

    直接继承View的控件,在draw方法中处理padding;直接继承ViewGroup的控件需要在onMeasure和onLayout处理padding。

3、尽量不要在View中使用Handler,没必要

    View内部的post系列方法完全可以替代handler的作用

4、View中如果有线程或者动画,需要及时停止,参考View#onDetacheedFromWindow

5、View带有滑动嵌套情形时,需要处理好滑动冲突



你可能感兴趣的:(Android)