您的位置:首页 > 移动开发 > Android开发

View的工作原理

2016-07-27 10:54 465 查看

一、ViewRoot和DecorView

1、ViewRoot

1)ViewRoot对应于ViewRootImpl类,它是连接WindowManager和DecorView的纽带,View的三大流程均通过ViewRoot来完成。

2)在Activity线程中,当Activity对象被创建完毕后,会将DecorView添加到Window中,同时会创建ViewRootImpl对象,并将ViewRootImpl对象和DecorView建立连接。

3)View的绘制流程

-纵向:从ViewRoot的performTraversals开始->performMeasure->performLayout->performDraw
-横向:

-performMeasure->measure->onMeasure
-performLayout->layout->onLayout
-performDraw->draw->onDraw

2、DecorView

1)一般情况下,DecorView内部会包含一个LinearLayout,里面分为上下两部分,分别为标题栏和内容栏,我们设置布局的时候就是调用setContentView方法。

2)DecorView是一个FrameLyout,View层的事件都先经过它,然后分发给子View。

二、MeasureSpec

1、概念

MeasureSpec代表一个32位的int值,高2位代表SpecMode,低30位代表SpecSize。

1)SpecMode代表测量模式,有3种

-UNSPECIFIED:父容器不对View有任何限制,要多大给多大。一般用于系统内部。
-EXACTLY:父容器已经检测到View所需要的精确大小,这个时候View的最终大小就是SpecSize所指定的值。对应LayoutParams中的match_parent和具体的数值。
-AT_MOST:父容器指定了一个可用大小即SpecSize,View的大小不能大于这个值。对应LayoutParams中的wrap_content。

2)SpecSize代表在某种测量模式下的规格大小。

2、MeasureSpec和LayoutParams的对应关系

1)DecorView

其Measure由窗口尺寸和自身Layoutparams来决定。调用getRootMeasureSpec方法,返回MeasureSpec

-LayoutParams.MATCH_PARENT:窗口尺寸+EXACTLY。
-LayoutParams.WRAP_CONTENT:窗口尺寸+AT_MOST。
-默认:Layoutparams的尺寸+EXACTLY。

2)普通View

其Measure由父容器的MeasureSpec和自身Layoutparams来决定。调用getChildMeasureSpec方法,返回MeasureSpec

-parentSpecMode:EXACTLY

-childLayoutParams.dp/px:child尺寸+EXACTLY。
-childLayoutParams.match_parent:parent尺寸+EXACTLY。
-childLayoutParams.wrap_content:parent尺寸+AT_MOST。

-parentSpecMode:AT_MOST

-childLayoutParams.dp/px:child尺寸+EXACTLY。
-childLayoutParams.match_parent:parent尺寸+AT_MOST。
-childLayoutParams.wrap_content:parent尺寸+AT_MOST。

-parentSpecMode:UNSPCIFIED

-childLayoutParams.dp/px:child尺寸+EXACTLY。
-childLayoutParams.match_parent:0。
-childLayoutParams.wrap_content:0。

三、View的工作流程

1、measure过程

1)View的measure过程:

-onMeasure:调用setMeasureDimension
-setMeasureDimension:设置View宽高的测量值,参数通过getDefaultSize获取。 -getDefaultSize:返回measureSpec中的specSize,也就是View测量后的大小,第一个参数通过getSuggestedMinimumWidth/getSuggestedMinimumHeight获取,第二个参数为measureSpec。
-getSuggestedMinimumWidth/getSuggestedMinimumHeight:如果View没有设置背景,返回android:minWidth这个属性所指定的值,可以为0;如果View设置了背景,返回的就是View在UNSPECIFIED情况下的测量宽高。

2)ViewGroup的measure过程

ViewGroup是一个抽象类,并没有定义其测量的具体过程,而是提供了一个measureChildren的方法,具体过程需要各个子类去实现。

3)获取View的宽高:

因为measure过程和Activity的生命周期不同步,所以在onCreate、onStart、onResume中不能保证绝对获取到。

-onWindowFocusChanged:View已经初始化完毕,可以获取到View宽高。
-view.post(runnable):post将一个runnable投递到消息队列的队尾,然后等待Looper调用此runnable的时候,View已经初始化好了。
-ViewTreeObserver:使用ViewTreeObserver的回调,比如OnGlobalLayoutListener这个接口,当View树的状态发生变化或者View树内部的View可见性改变时,onGlobalLayout方法将被调用,这时就可以获取到View宽高。

2、layout过程

1)首先通过setFrame方法设定View的四个顶点的位置

2)调用onLayout方法,父容器确定子元素的位置。

3、draw过程

1)绘制背景:background.draw(canvas)

2)绘制自己:onDraw

3)绘制Children:dispatchDraw

4)绘制装饰:onDrawScrollBars

注意:

1)一个View不需要绘制内容,那么标志位WILL_NOT_DRAW设为true,系统会自动进行优化。

2)默认情况下,View没有启用这个标志位,ViewGroup则默认启动。

3)当自定义控件继承自ViewGroup并且自身不具备绘制功能,就可以开启这个标志位,从而便于系统优化。

四、自定义View

1、自定义View的分类

1)继承View重写onDraw方法

实现一些不规则的效果,但是需要自己处理wrap_content和padding这两种情况。

2)继承ViewGroup派生特殊的Layout

实现几个View组合的效果,但是需要自己处理ViewGroup的measure和layout过程。

3)继承特定的View

用于扩展已有的View,不需要自己处理wrap_content和padding这两种情况。

4)继承特定的ViewGroup

实现几个View组合的效果,不需要自己处理ViewGroup的measure和layout过程。

2、自定义中的注意事项

1)让View支持wrap_content和padding。
2)尽量不要在View使用Handler。
3)View中如果有线程或者动画,需要及时停止。
4)处理好View中的滑动冲突。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息