ImageVerifierCode 换一换
格式:DOCX , 页数:15 ,大小:316.28KB ,
资源ID:3978029      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/3978029.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(View绘制流程.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

View绘制流程.docx

1、View绘制流程View绘制流程第一步:递归measure源码分析/final方法,子类不可重写public final void measure(int widthMeasureSpec, int heightMeasureSpec) ./回调onMeasure()方法onMeasure(widthMeasureSpec, heightMeasureSpec);这个方法的两个参数都是父View传递过来的,代表了父view的规格。他由两部分组成,高2位表示MODE,低30位表示size。/View的onMeasure默认实现方法protected void onMeasure(int widt

2、hMeasureSpec, int heightMeasureSpec) setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);对于非ViewGroup的View而言,通过调用上面默认的onMeasure即可完成View的测量。setMeasuredDimension函数是一个很关键的函数,它完成了对View的成员变量mMeasuredWidth和mMeasur

3、edHeight变量赋值。public static int getDefaultSize(int size, int measureSpec) int result = size;/通过MeasureSpec解析获取mode与sizeint specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec);switch (specMode) case MeasureSpec.UNSPECIFIED: result = size; break; case MeasureSpe

4、c.AT_MOST: case MeasureSpec.EXACTLY: result = specSize; break; return result;protected int getSuggestedMinimumWidth() return (mBackground = null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth();protected int getSuggestedMinimumHeight() return (mBackground = null) ? mMinHeight : max(mMinHe

5、ight, mBackground.getMinimumHeight();在ViewGroup中定义了measureChildren, measureChild, measureChildWith-Margins方法来对子视图进行测量,measureChildren内部实质只是循环调用measureChild。protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) /获取子视

6、图的LayoutParamsfinal MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();/调整MeasureSpec/通过这两个参数以及子视图本身LayoutParams来共同决定子视图的测量规格final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin + widthUsed, lp.wi

7、dth);final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin + heightUsed, lp.height);/调运子View的measure方法,子View的measure中会回调子View的/onMeasure方法child.measure(childWidthMeasureSpec, childHeightMeasureSpec);该方法就是对父视图提供的m

8、easureSpec参数结合自身的LayoutParams参数进行了调整,然后再来调用child.measure()方法,具体通过方法getChildMeasureSpec来进行参数调整。public static int getChildMeasureSpec(int spec, int padding, int childDimension) /获取当前Parent View的Mode和Size int specMode = MeasureSpec.getMode(spec); int specSize = MeasureSpec.getSize(spec); /获取Parent size

9、与padding差值(也就是Parent剩余大小),若差值小于0直接返回0 int size = Math.max(0, specSize - padding); /定义返回值存储变量 int resultSize = 0; int resultMode = 0; /依据当前Parent的Mode进行switch分支逻辑 switch (specMode) / Parent has imposed an exact size on us /默认Root View的Mode就是EXACTLY case MeasureSpec.EXACTLY: if (childDimension = 0) /如

10、果child的layout_wOrh属性在xml或者java中给予具体大/于等于0的数值 /设置child的size为真实layout_wOrh属性值,mode为EXACTLY resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; else if (childDimension = LayoutParams.MATCH_PARENT) /如果child的layout_wOrh属性在xml或者java中给予/MATCH_PARENT / Child wants to be our size. So be it. /设置chi

11、ld的size为size,mode为EXACTLY resultSize = size; resultMode = MeasureSpec.EXACTLY; else if (childDimension = LayoutParams.WRAP_CONTENT) /如果child的layout_wOrh属性在xml或者java中给予/WRAP_CONTENT /设置child的size为size,mode为AT_MOST / Child wants to determine its own size. It cant be / bigger than us. resultSize = size

12、; resultMode = MeasureSpec.AT_MOST; break; . /其他Mode分支类似 /将mode与size通过MeasureSpec方法整合为32位整数返回 return MeasureSpec.makeMeasureSpec(resultSize, resultMode);用View的getMeasuredWidth()和getMeasuredHeight()方法来获取View测量的宽高,必须保证这两个方法在onMeasure流程之后被调用才能返回有效值。MeasureSpec(View的内部类)测量规格为int型,值由高2位规格模式specMode和低30位具

13、体尺寸specSize组成。其中specMode只有三种值:MeasureSpec.EXACTLY /确定模式,父View希望子View的大小是确定的,由specSize决定;MeasureSpec.AT_MOST /最多模式,父View希望子View的大小最多是specSize指定的值;MeasureSpec.UNSPECIFIED /未指定模式,父View完全依据子View的设计值来决定;View绘制流程第二步:递归layout源码分析ViewGroup的layout方法,如下:Overridepublic final void layout(int l, int t, int r, in

14、t b) . super.layout(l, t, r, b);.调运了View父类的layout方法,所以我们看下View的layout源码,如下:public void layout(int l, int t, int r, int b) /实质都是调用setFrame方法把参数分别赋值给mLeft、mTop、mRight和/mBottom这几个变量/判断View的位置是否发生过变化,以确定有没有必要对当前的View进行重新/layout boolean changed = isLayoutModeOptical(mParent) ? setOpticalFrame(l, t, r, b)

15、 : setFrame(l, t, r, b);if (changed | (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) = PFLAG_LAYOUT_REQUIRED) onLayout(changed, l, t, r, b);/ViewGroup的onLayout方法,如下:Overrideprotected abstract void onLayout(boolean changed,int l, int t, int r, int b);关于getWidth()、getHeight()和getMeasuredWidth()、getMeasuredHe

16、ight()这两对方法之间的区别public final int getMeasuredWidth () return mMeasuredWidth & MEASURED_SIZE_MASK;public final int getMeasuredHeight() return mMeasuredHeight & MEASURED_SIZE_MASK;public final int getWidth() return mRight - mLeft;public final int getHeight() return mBottom - mTop;View.layout方法可被重载,View

17、Group.layout为final的不可重载,ViewGroup.onLayout为abstract的,子类必须重载实现自己的位置逻辑。凡是layout_XXX的布局属性基本都针对的是包含子View的ViewGroup的,当对一个没有父容器的View设置相关layout_XXX属性是没有任何意义的使用View的getWidth()和getHeight()方法来获取View测量的宽高,必须保证这两个方法在onLayout流程之后被调用才能返回有效值View绘制流程第三步:递归draw源码分析ViewGroup没有重写View的draw方法,所以如下直接从View的draw方法开始public

18、void draw(Canvas canvas) / Step 1, draw the background, if needed if (!dirtyOpaque) drawBackground(canvas); / skip step 2 & 5 if possible (common case) / Step 2, save the canvas layers if (drawTop) canvas.saveLayer(left, top, right, top + length, null, flags); / Step 3, draw the content if (!dirtyOp

19、aque) onDraw(canvas); / Step 4, draw the children dispatchDraw(canvas); / Step 5, draw the fade effect and restore layers if (drawTop) matrix.setScale(1, fadeHeight * topFadeStrength); matrix.postTranslate(left, top); fade.setLocalMatrix(matrix); p.setShader(fade); canvas.drawRect(left, top, right,

20、top + length, p); / Step 6, draw decorations (scrollbars) onDrawScrollBars(canvas);private void drawBackground(Canvas canvas) /获取xml中通过android:background属性或者代码中/setBackgroundColor()、setBackgroundResource()等方法进行赋值的背景/Drawable final Drawable background = mBackground; . /根据layout过程确定的View位置来设置背景的绘制区域 i

21、f (mBackgroundSizeChanged) background.setBounds(0, 0, mRight - mLeft, mBottom - mTop); mBackgroundSizeChanged = false; rebuildOutline(); . /调用Drawable的draw()方法来完成背景的绘制工作 background.draw(canvas); ./View的onDraw方法, 这是一个空方法。因为每个View的内容部分是各不相同的,/所以需要由子类去实现具体逻辑。protected void onDraw(Canvas canvas) / View的

22、dispatchDraw()方法是一个空方法,如果View包含子类需要重写他,所/以我们有必要看下ViewGroup的dispatchDraw方法源码Overrideprotected void dispatchDraw(Canvas canvas) .final int childrenCount = mChildrenCount; final View children = mChildren; for (int i = 0; i = 0; i-) more |= drawChild(canvas, child, drawingTime); / ViewGroup确实重写了View的dis

23、patchDraw()方法,该方法内部会遍历每个子/View,然后调用drawChild()方法,我们可以看下ViewGroup的drawChild方法protected boolean drawChild(Canvas canvas, View child, long drawingTime) return child.draw(canvas, this, drawingTime);drawChild()方法调运了子View的draw()方法。所以说ViewGroup类已经为我们重写了dispatchDraw()的功能实现,我们一般不需要重写该方法,但可以重载父类函数实现具体的功能。在获取画

24、布剪切区时会自动处理掉padding,子View获取Canvas不用关注这些逻辑,只用关心如何绘制即可。默认情况下子View的ViewGroup.drawChild绘制顺序和子View被添加的顺序一致,但是你也可以重载ViewGroup.getChildDrawingOrder()方法提供不同顺序。View的invalidate方法源码分析View类中的一些invalidate方法/This must be called from a UI thread. To call from a non-UI thread, / call postInvalidate()public void inva

25、lidate(Rect dirty) final int scrollX = mScrollX; final int scrollY = mScrollY; /实质还是调运invalidateInternal方法 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, dirty.right - scrollX, dirty.bottom - scrollY, true, false);/This must be called from a UI thread. To call from a non-UI thread, /

26、call postInvalidate()public void invalidate(int l, int t, int r, int b) final int scrollX = mScrollX; final int scrollY = mScrollY; /实质还是调运invalidateInternal方法 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false);/This must be called from a UI thread. To call from a no

27、n-UI thread, / call postInvalidate()public void invalidate() /invalidate的实质还是调运invalidateInternal方法 invalidate(true); /this function can be called with invalidateCache set to false to /skip that invalidation step void invalidate(boolean invalidateCache) /实质还是调运invalidateInternal方法invalidateInternal(

28、0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);/所有invalidate的最终调运方法void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate) . / Propagate the damage rectangle to the parent view. final AttachInfo ai = mAttachInfo; final ViewParent p = mParent

29、; if (p != null & ai != null & l r & t b) final Rect damage = ai.mTmpInvalRect; /设置刷新区域 damage.set(l, t, r, b); /传递调运Parent ViewGroup的invalidateChild方法 p.invalidateChild(this, damage); .View的invalidate(invalidateInternal)方法实质是将要刷新区域直接传递给了父ViewGroup的invalidateChild方法,在invalidate中,调用父View的invalidateChild,这是一个从当前向上级父View回溯的过程ViewGroup的invalidateChild方法public final void invalidateChild(View child, final Rect dirty) ViewParent parent = this; final AttachInfo attachInfo = mAttachInfo;

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1