View绘制流程Word文档下载推荐.docx
- 文档编号:16884954
- 上传时间:2022-11-26
- 格式:DOCX
- 页数:15
- 大小:316.28KB
View绘制流程Word文档下载推荐.docx
《View绘制流程Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《View绘制流程Word文档下载推荐.docx(15页珍藏版)》请在冰豆网上搜索。
intspecSize=MeasureSpec.getSize(measureSpec);
switch(specMode){
caseMeasureSpec.UNSPECIFIED:
result=size;
break;
caseMeasureSpec.AT_MOST:
caseMeasureSpec.EXACTLY:
result=specSize;
}
returnresult;
protectedintgetSuggestedMinimumWidth(){
return(mBackground==null)?
mMinWidth:
max(mMinWidth,
mBackground.getMinimumWidth());
protectedintgetSuggestedMinimumHeight(){
mMinHeight:
max(mMinHeight,
mBackground.getMinimumHeight());
在ViewGroup中定义了measureChildren,measureChild,measureChildWith-
Margins方法来对子视图进行测量,measureChildren内部实质只是循环调用measureChild。
protectedvoidmeasureChildWithMargins(Viewchild,
intparentWidthMeasureSpec,intwidthUsed,
intparentHeightMeasureSpec,intheightUsed){
//获取子视图的LayoutParams
finalMarginLayoutParamslp=(MarginLayoutParams)
child.getLayoutParams();
//调整MeasureSpec
//通过这两个参数以及子视图本身LayoutParams来共同决定子视图的测量规格
finalintchildWidthMeasureSpec=
getChildMeasureSpec(parentWidthMeasureSpec,
mPaddingLeft+mPaddingRight+lp.leftMargin+lp.rightMargin
+widthUsed,lp.width);
finalintchildHeightMeasureSpec=
getChildMeasureSpec(parentHeightMeasureSpec,
mPaddingTop+mPaddingBottom+lp.topMargin+lp.bottomMargin
+heightUsed,lp.height);
//调运子View的measure方法,子View的measure中会回调子View的//onMeasure方法
child.measure(childWidthMeasureSpec,childHeightMeasureSpec);
该方法就是对父视图提供的measureSpec参数结合自身的LayoutParams参数进行了调整,然后再来调用child.measure()方法,具体通过方法getChildMeasureSpec来进行参数调整。
publicstaticintgetChildMeasureSpec(intspec,intpadding,int
childDimension){
//获取当前ParentView的Mode和Size
intspecMode=MeasureSpec.getMode(spec);
intspecSize=MeasureSpec.getSize(spec);
//获取Parentsize与padding差值(也就是Parent剩余大小),若差值小于0直接返回0
intsize=Math.max(0,specSize-padding);
//定义返回值存储变量
intresultSize=0;
intresultMode=0;
//依据当前Parent的Mode进行switch分支逻辑
switch(specMode){
//Parenthasimposedanexactsizeonus
//默认RootView的Mode就是EXACTLY
if(childDimension>
=0){
//如果child的layout_wOrh属性在xml或者java中给予具体大
//于等于0的数值
//设置child的size为真实layout_wOrh属性值,mode为EXACTLY
resultSize=childDimension;
resultMode=MeasureSpec.EXACTLY;
}elseif(childDimension==LayoutParams.MATCH_PARENT){
//如果child的layout_wOrh属性在xml或者java中给予
//MATCH_PARENT
//Childwantstobeoursize.Sobeit.
//设置child的size为size,mode为EXACTLY
resultSize=size;
}elseif(childDimension==LayoutParams.WRAP_CONTENT){
//WRAP_CONTENT
//设置child的size为size,mode为AT_MOST
//Childwantstodetermineitsownsize.Itcan'
tbe
//biggerthanus.
resultMode=MeasureSpec.AT_MOST;
......
//其他Mode分支类似
//将mode与size通过MeasureSpec方法整合为32位整数返回
returnMeasureSpec.makeMeasureSpec(resultSize,resultMode);
·
用View的getMeasuredWidth()和getMeasuredHeight()方法来获取View测量的宽高,必须保证这两个方法在onMeasure流程之后被调用才能返回有效值。
MeasureSpec(View的内部类)测量规格为int型,值由高2位规格模式specMode和低30位具体尺寸specSize组成。
其中specMode只有三种值:
MeasureSpec.EXACTLY//确定模式,父View希望子View的大小是确定的,由specSize决定;
MeasureSpec.AT_MOST//最多模式,父View希望子View的大小最多是specSize指定的值;
MeasureSpec.UNSPECIFIED//未指定模式,父View完全依据子View的设计值来决定;
View绘制流程第二步:
递归layout源码分析
ViewGroup的layout方法,如下:
@Override
publicfinalvoidlayout(intl,intt,intr,intb){
super.layout(l,t,r,b);
.....
调运了View父类的layout方法,所以我们看下View的layout源码,如下:
publicvoidlayout(intl,intt,intr,intb){
//实质都是调用setFrame方法把参数分别赋值给mLeft、mTop、mRight和//mBottom这几个变量
//判断View的位置是否发生过变化,以确定有没有必要对当前的View进行重新//layout
booleanchanged=isLayoutModeOptical(mParent)?
setOpticalFrame(l,t,r,b):
setFrame(l,t,r,b);
if(changed||(mPrivateFlags&
PFLAG_LAYOUT_REQUIRED)==
PFLAG_LAYOUT_REQUIRED){
onLayout(changed,l,t,r,b);
//ViewGroup的onLayout方法,如下:
protectedabstractvoidonLayout(booleanchanged,
intl,intt,intr,intb);
关于getWidth()、getHeight()和getMeasuredWidth()、getMeasuredHeight()这两对方法之间的区别
publicfinalintgetMeasuredWidth(){
returnmMeasuredWidth&
MEASURED_SIZE_MASK;
publicfinalintgetMeasuredHeight(){
returnmMeasuredHeight&
publicfinalintgetWidth(){
returnmRight-mLeft;
publicfinalintgetHeight(){
returnmBottom-mTop;
View.layout方法可被重载,ViewGroup.layout为final的不可重载,ViewGroup.onLayout为abstract的,子类必须重载实现自己的位置逻辑。
凡是layout_XXX的布局属性基本都针对的是包含子View的ViewGroup的,当对一个没有父容器的View设置相关layout_XXX属性是没有任何意义的
使用View的getWidth()和getHeight()方法来获取View测量的宽高,必须保证这两个方法在onLayout流程之后被调用才能返回有效值
View绘制流程第三步:
递归draw源码分析
ViewGroup没有重写View的draw方法,所以如下直接从View的draw方法开始
publicvoiddraw(Canvascanvas){
//Step1,drawthebackground,ifneeded
if(!
dirtyOpaque){
drawBackground(canvas);
//skipstep2&
5ifpossible(commoncase)
//Step2,savethecanvas'
layers
if(drawTop){
canvas.saveLayer(left,top,right,top+length,null,flags);
//Step3,drawthecontent
dirtyOpaque)onDraw(canvas);
//Step4,drawthechildren
dispatchDraw(canvas);
//Step5,drawthefadeeffectandrestorelayers
matrix.setScale(1,fadeHeight*topFadeStrength);
matrix.postTranslate(left,top);
fade.setLocalMatrix(matrix);
p.setShader(fade);
canvas.drawRect(left,top,right,top+length,p);
//Step6,drawdecorations(scrollbars)
onDrawScrollBars(canvas);
privatevoiddrawBackground(Canvascanvas){
//获取xml中通过android:
background属性或者代码中
//setBackgroundColor()、setBackgroundResource()等方法进行赋值的背景
//Drawable
finalDrawablebackground=mBackground;
//根据layout过程确定的View位置来设置背景的绘制区域
if(mBackgroundSizeChanged){
background.setBounds(0,0,mRight-mLeft,mBottom-mTop);
mBackgroundSizeChanged=false;
rebuildOutline();
//调用Drawable的draw()方法来完成背景的绘制工作
background.draw(canvas);
//View的onDraw方法,这是一个空方法。
因为每个View的内容部分是各不相同的,//所以需要由子类去实现具体逻辑。
protectedvoidonDraw(Canvascanvas){
//View的dispatchDraw()方法是一个空方法,如果View包含子类需要重写他,所//以我们有必要看下ViewGroup的dispatchDraw方法源码
protectedvoiddispatchDraw(Canvascanvas){
finalintchildrenCount=mChildrenCount;
finalView[]children=mChildren;
for(inti=0;
i<
childrenCount;
i++){
if((child.mViewFlags&
VISIBILITY_MASK)==VISIBLE||
child.getAnimation()!
=null){
more|=drawChild(canvas,child,drawingTime);
//Drawanydisappearingviewsthathaveanimations
if(mDisappearingChildren!
for(inti=disappearingCount;
i>
=0;
i--){
//ViewGroup确实重写了View的dispatchDraw()方法,该方法内部会遍历每个子//View,然后调用drawChild()方法,我们可以看下ViewGroup的drawChild方法
protectedbooleandrawChild(Canvascanvas,Viewchild,
longdrawingTime){
returnchild.draw(canvas,this,drawingTime);
drawChild()方法调运了子View的draw()方法。
所以说ViewGroup类已经为我们重写了dispatchDraw()的功能实现,我们一般不需要重写该方法,但可以重载父类函数实现具体的功能。
在获取画布剪切区时会自动处理掉padding,子View获取Canvas不用关注这些逻辑,只用关心如何绘制即可。
默认情况下子View的ViewGroup.drawChild绘制顺序和子View被添加的顺序一致,但是你也可以重载ViewGroup.getChildDrawingOrder()方法提供不同顺序。
View的invalidate方法源码分析
View类中的一些invalidate方法
//ThismustbecalledfromaUIthread.Tocallfromanon-UIthread,
//callpostInvalidate()
publicvoidinvalidate(Rectdirty){
finalintscrollX=mScrollX;
finalintscrollY=mScrollY;
//实质还是调运invalidateInternal方法
invalidateInternal(dirty.left-scrollX,dirty.top-scrollY,
dirty.right-scrollX,dirty.bottom-scrollY,true,false);
publicvoidinvalidate(intl,intt,intr,intb){
invalidateInternal(l-scrollX,t-scrollY,r-scrollX,b-scrollY,true,false);
publicvoidinvalidate(){
//invalidate的实质还是调运invalidateInternal方法
invalidate(true);
//thisfunctioncanbecalledwithinvalidateCachesettofalseto//skipthatinvalidationstep
voidinvalidate(booleaninvalidateCache){
invalidateInternal(0,0,mRight-mLeft,mBottom-mTop,
invalidateCache,true);
//所有invalidate的最终调运方法
voidinvalidateInternal(intl,intt,intr,intb,booleaninvalidateCache,booleanfullInvalidate){
//Propagatethedamagerectangletotheparentview.
finalAttachInfoai=mAttachInfo;
finalViewParentp=mParent;
if(p!
=null&
&
ai!
l<
r&
t<
b){
finalRectdamage=ai.mTmpInvalRect;
//设置刷新区域
damage.set(l,t,r,b);
//传递调运ParentViewGroup的invalidateChild方法
p.invalidateChild(this,damage);
View的invalidate(invalidateInternal)方法实质是将要刷新区域直接传递给了父ViewGroup的invalidateChild方法,在invalidate中,调用父View的invalidateChild,这是一个从当前向上级父View回溯的过程
ViewGroup的invalidateChild方法
publicfinalvoidinvalidateChild(Viewchild,finalRectdirty){
ViewParentparent=this;
finalAttachInfoattachInfo=mAttachInfo;
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- View 绘制 流程