自定义view之view的工作流程
来源:互联网 发布:超人打水软件 编辑:程序博客网 时间:2024/05/16 18:06
自定义view是我们开发中经常遇到的问题,总结下来之后发现,对于自定义view来说,了解他的工作流程对我们自定义控件的时候有很大的帮助。
1、我们先来看看viewroot和decorview
viewroot对应于viewrootimpl类,它是链接windowmanager和decorview的纽带,view的三大流程均是通过viewroot来完成的。view的绘制流程就是从viewroot的performtraversals方法开始的,它通过measure、layout,draw三个方法,最终才绘制出view的。measure用来测量view的宽和高,layout用来确定view在父容器之中的位置,draw是负责将view绘制在频幕上。大致流程如下:
measure过程决定了控件的高和宽,当measure过程完成后,可以通过getmeasurewidth和getmeasureheight来获取view的高和宽,在几乎所有的情况下,他都等于view的实际高和宽。layout决定里四个顶点的坐标和实际view的宽和高。完成后可以通过gettop、getleft、getright、getleft、getbottom方法来获取。draw方法决定了view的显示。
2、理解measurespec
measurespec代表一个32位的int值,高两位代表SpecMode,第三十为表示specsize。specMode代表测量模式,specSize代表测量规格大小。它将specmode和specsize打包成int值,来避免过多的对象内存分配,specmode有以下几种方式:
UNspecified 父容器不对view有任何限制,要多大给多大,一般用于系统内部,表示一种测量状态;
exactly 父容器已经检测出view所需要的精确值,这时候view的最终大小就是specsize 所指定的值,它对于layoutparams中的match_parent和具体数值这两种模式。
at_most 父容器制定了大小值,view的最大值不能大于父容器所指定的值。适用于layoutparams中的wrap_content;我们不能直接通过制定view的layoutparams来制定view的大小,他必须配合父容器的measurespec来一起使用,对于decorview来说,其measurespec由窗口的尺寸和自身的layoutparams来决定。对于普通view其measurespec有父容器的measurespec和自身的layoutparams来决定。
layoutparams.match_parent 精确模式,大小就是窗口大小;
layoutparams.wrap_content 最大模式,大小不定,但是大小不能超过窗口的大小;
固定大小 精确模式,大小为layoutparams中所指定的大小;
measurespec一旦确定后,就可以通过onmeasure来确定view的宽和高。view 的measure由viewgroup传递而来,先看一下viewgroup的measureChildWithMargins:
protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin + widthUsed, lp.width); final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin + heightUsed, lp.height); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); }
上边的方法对view子元素进行measure方法,在对子元素进行measure方法之前,我们先通过getchildmeasurespec方法获取子元素的measure,通过上边的代码可以看出来子元素的measure和父容器的measure和自身的layoutparams有过,还和view的margin和padding有关。可以看看getchildmeasurespec方法:
public static int getChildMeasureSpec(int spec, int padding, int childDimension) { int specMode = MeasureSpec.getMode(spec); int specSize = MeasureSpec.getSize(spec); int size = Math.max(0, specSize - padding); int resultSize = 0; int resultMode = 0; switch (specMode) { // Parent has imposed an exact size on us case MeasureSpec.EXACTLY: if (childDimension >= 0) { resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } else if (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size. So be it. resultSize = size; resultMode = MeasureSpec.EXACTLY; } else if (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size. It can't be // bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST; } break; // Parent has imposed a maximum size on us case MeasureSpec.AT_MOST: if (childDimension >= 0) { // Child wants a specific size... so be it resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } else if (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size, but our size is not fixed. // Constrain child to not be bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST; } else if (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size. It can't be // bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST; } break; // Parent asked to see how big we want to be case MeasureSpec.UNSPECIFIED: if (childDimension >= 0) { // Child wants a specific size... let him have it resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } else if (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size... find out how big it should // be resultSize = 0; resultMode = MeasureSpec.UNSPECIFIED; } else if (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size.... find out how // big it should be resultSize = 0; resultMode = MeasureSpec.UNSPECIFIED; } break; } return MeasureSpec.makeMeasureSpec(resultSize, resultMode); }对于上面的代码,我们不难理解,他是通过父元素的measurespec和子元素自身的layoutparams来确定子元素的measurespec。代码中的padding是指父元素所占用的空间大小。子元素的大小为父元素的大小减去padding。它清楚展示了普通子view的measurespec的创建规则,为了更清晰的理解他的逻辑,这里提供了如下的表格:
在下一节我们将继续讲解view的工作流程。
请大家跟上一起进步,一起告别码农!!!!!!!!
- 自定义view之view的工作流程
- 自定义View--View的工作流程
- View的工作流程
- View的工作流程
- View的工作流程
- View的工作流程
- View的工作流程
- Android自定义View之View的绘制流程
- 自定义view:view的绘制流程
- Android--View的工作流程
- Android View的工作流程
- View的工作原理(自定义View)
- 自定义View(一)---View的基础概念、工作流程以及生命周期的理解
- View的工作原理(二)之 View的工作流程
- 自定义view的绘制流程
- 自定义view的基本流程
- android 自定义view的流程
- View的工作原理(二)----View的工作流程
- Crontab详述
- datatable的一些小技巧
- Java多线程20:多线程下的其他组件之CountDownLatch、Semaphore、Exchanger
- PHP中的stdClass类
- MySQL5.7安装与配置(YUM)
- 自定义view之view的工作流程
- Java多线程21:多线程下的其他组件之CyclicBarrier、Callable、Future和FutureTask
- ubuntu14.04安装kinect1驱动
- ARM各种异常返回地址的计算
- Oracle 查询表信息
- Computer Graphic with opengl第一个例子
- redis的5种数据类型的使用
- 携程移动端优化
- PHP开发小技巧⑨—获取url中的各个参数