自定义View

澳门新葡亰网站注册 3

Android中的任何一个布局、任何一个控件其实都是直接或间接继承自View实现的,当然也包括我们在平时开发中所写的各种炫酷的自定义控件了,所以学习View的工作原理对于我们来说显得格外重要,本篇博客,我们将一起深入学习Android中View的工作原理。

4.1 初始ViewRoot和DecorView
澳门新葡亰网站注册,View的绘制流程是从ViewRoot的performTraversal的开始的。经过measure,layout,draw三个过程。
performTraversal会依次调用performMeasure,performLayout,performDraw来完成顶级View的measure,layout和draw过程。performMeasure方法中会调用measure方法,在measure方法中又会调用onMeasure方法,在onMeasure方法中会对所有的子元素进行measure过程,这个时候measure流程就从父容器传递到子元素了,这样就完成了一次measure过程,layout和draw的过程类似。
(1)measure过程决定了View的宽高,几乎在所有情况下,这个宽高都等于View最终的宽高。getMeasuredHeight(),getMeasuredWidth()来得到测量宽高。
(2)layout过程决定了View四个顶点的位置,和View实际的宽高。通过getHeight()和getWidth()来得到实际的宽高。
(3)draw过程决定view的显示。
DecorView是一个FrameLayout,包含了一个竖直方向的LinearLayout,上面是标题栏,下面是内容。
4.1 理解MeasureSpec
(1)MeasureSpec和LayoutParams的对应关系。
在View测量的时候,系统会将LayoutParams在父容器的约束下转换成MeasureSpec,在根据MeasureSpec来决定View测量后的宽高。
MeasureSpec不是唯一由LayoutParams决定的,而是和父容器一起决定的。对于DecorView,它的MeasureSpec是由窗口的大小和自身的LayoutParams确定的。
(2)普通view的MeasureSpec的创建规则
当View采用固定宽高时,不管父容器采用什么MeasureSpec,View的MeasureSpec都是精确模式,大小等于LayoutParams中的大小。
当View采用match_parent时,如果父容器是精确模式,那么view也是精确模式,大小是父容器剩余的大小。如果父容器是最大模式,那么view也是最大模式,大小不超过父容器的剩余空间。
当View采用wrap_content时,不管父容器是什么模式,View都是最大模式,大小是不超过父容器剩余的大小。
4.3 View的工作流程
(1)measure过程
view的测量过程由measure方法(final)完成,在measure方法中又会调用onMeasure方法,onMeasure会调用setMeasuredDimension方法,setMeasuredDimension会设置View宽高的测量值。当View的SpecMode是AT_MOST和EXACTLY时,getDefaultSize返回的是measureSpec中的specSize的大小,而当View的SpecMode是UNSPECIFIED的时候
返回的是size,是getSuggestedMinimumWidth的返回值,如果View没有设置背景,那么返回的是android:midWidth这个属性,如果设置了背景,返回的是android:minWidth和背景最小宽度中两者的的最大值。

ViewRoot和DecorView

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

2.View的绘制流程从ViewRoot的performTraversals开始,经过measure、layout和draw三个过程才可以把一个View绘制出来,其中measure用来测量View的宽高,layout用来确定View在父容器中的放置位置,而draw则负责将View绘制到屏幕上。

3.performTraversals会依次调用performMeasure、performLayout和performDraw三个方法,这三个方法分别完成顶级View的measure、layout和draw这三大流程。其中performMeasure中会调用measure方法,在measure方法中又会调用onMeasure方法,在onMeasure方法中则会对所有子元素进行measure过程,这样就完成了一次measure过程;子元素会重复父容器的measure过程,如此反复完成了整个View数的遍历。

澳门新葡亰网站注册 1

measure过程决定了View的宽/高,完成后可通过getMeasuredWidth/getMeasureHeight方法来获取View测量后的宽/高。Layout过程决定了View的四个顶点的坐标和实际View的宽高,完成后可通过getTop、getBotton、getLeft和getRight拿到View的四个定点坐标。Draw过程决定了View的显示,完成后View的内容才能呈现到屏幕上。

DecorView作为顶级View,一般情况下它内部包含了一个竖直方向的LinearLayout,里面分为两个部分(具体情况和Android版本和主题有关),上面是标题栏,下面是内容栏。在Activity通过setContextView所设置的布局文件其实就是被加载到内容栏之中的。

//获取内容栏
ViewGroup content = findViewById(R.android.id.content);
//获取我们设置的Viewcontext.getChildAt(0);
DecorView其实是一个FrameLayout,View层的事件都先经过DecorView,然后才传给我们的View。

澳门新葡亰网站注册 2

澳门新葡亰网站注册 3