Android View的绘制过程复习小结

这是我参与8月更文应战的第20天,活动概略查看:8月更文应战

Android View的制作进程

Android View的制作进程温习小结

DecorView是一个运用窗口的根容器,它本质上是一个FrameLayout.

DecorView有唯一一个子View,是一个笔直的LinearLayout,包括两个子元素:Ti接口类型tleView(ActionBar的容器) 和 ContentView(窗口内容的容器).

ContentView是一个FrameLayout(andro变量名的命名规则id.R.id.content),咱们平常用的setContentView就是设置它的子View.

上图还表达了每个Activitcanvas3y都与一个Window(详细来说是PhoneView)相相关,用户界面则由Window所承载.

Windowapproach

Window即窗口,这个概念在Android Framework中的结束为变量是什么意思android.view.Window这个抽象类,这个抽象类是对Android体系中的窗口的抽象.

实践上 , 窗口是一个微观的appreciate思想 ,它是屏幕上用于制作各种UI元素和响运用户输入工作的一个矩形区域.

特色:

  • 独立制作 , 不与其他界面相互影响
  • 不会触发其他界面是输入工作

setConcanvas3tent变量英文Vieandroid电子市场w

在分析setContentView()办法前,咱们需求明晰:canvas这个办法仅仅android手机结束了Activity的ContentView的创建,而并没有实行View的制作流程.

当咱们自定义Activity继承自canvas下载android.app.Activity时分,调用的setContentView()办法是Activity类的,源码如下:

public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutapproveResID);
. . .
}

getWindow()会回来Activity所相关的PhoneWindocanvas交大w , 所以实践上调用的是PhoneWindow的setCont接口测验面试题entViapproachew()办法.

ViewRoot

View的制作是由ViewRoot来担任的.每个运用窗口的decorView都有一个canvas3与之相关的ViewRoot目标,这种相关联络是apple由WindowManager来保护的 , 是在Activity启动时建立的.ActivityThread.handleResumeActivity()办法建立了二者的相关联络.接口

当建立了decorView和ViewRoot的相关联络后,ViewRoot的requestLayout()办法会被调用,以结束运用程序用户android什么意思界面的初度布局.

实践被调用的是ViewRootImpl类的rappstoreequestLayout()办法.

@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
// 检查主张布局恳求的线程是否为主线程  
checkThread();
mandroid平板电脑价格LayoutRequested = true;
scandroid是什么手机牌子heduleTraversals();
}
}

scheduleTraversals(application)会向主线程发送一个”遍历”消息,毕竟会导致ViewRootImpl的performTraversals()办法appear被调用.

View的制作流程开端于ViewRoot的performTraversals()办法

perfo变量min表明什么类型的变量rmTraversals()依次调用performMeasurandroid是什么手机牌子e()、performLayout()和perandroid是什么手机牌子formDraw()三个办法,别离结束顶级View的制作。其间performMeasure()会调用measure(),measure()中又调用onMeasure(变量与函数),结束对其悉数子元素的measure进程,这样就结束了一次measureapplication进程接口;接android电子市场着子元素会重复父容器的measure进程,如此反复至结束整个View树的遍历(layout和draw同理)。

View的制作

View的整个制作流程能够接口分为以下3个阶段:

  • mandroid是什么手机牌子easure:判别是否需求从头核算view的巨细,需求的话则核算
  • layoiut:app下载 判别是否需求从头核canvas3算view的方位,需求的话则核算
  • draw: 判别是否需求从头制作view,需求的话则变量与函数从头制作

Android View的制作进程温习小结

measu接口无权限re阶段

此阶段的意图是核算出控件树中的各个控件要闪现其内容的话,需求多少规范.

起点是ViewRoandroid平板电脑价格otIm接口测验面试题pl的measureHierarchy()办法:

private boo接口测验lean measureHierarchy(final View host, final WindowManager.LayoutParams lp, final Resources res,
final int desiredWi变量与函数ndowWidth, final int desiredWindowHeight) {
// 传入的desiredWindowXxx为窗口规范
int childWidthMeasureSpec;
int childHeightMeasureSpec;
boocanvas什么意思lean windowSizeMayChange = false;
. . .
boolean goodMeasure = false;
if (!goodMeasure) {
childWidthMeasuandroid手机reSpec = getRootMeasureSpec(接口测验面试题desiredWindowWidth, lp.width);
childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
performMeasure(childWidthMeasureandroid手机Spec, childHeightMeasureSpec);
if (mWidth != host.getMeaappearsuredWidth() || mHeight != host.getMeasuredHeight()) {
windowSizeMayChange = true;
}
}
recanvas交大turn windowSizeMayChange;
}

measure源码:

/**
* 调用这个方approach法来算出一个Vcanvas翻译iew应该为多大。参数为父View对其宽高的捆绑信息。
* 实践的丈量作业在onMeasure()办法中进行
*/
public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
. . .
// 判别是否需求从头布局
// 若mPrivate接口和抽象类的差异Flags中包括PFLAG_FORCE_LAYOappearUT符号,则强制从头布局
// 比方调用ViCanvasew.requestLayout()会在mPrivateFlcanvas标签ags中加入此符号
final boolean forceLayout = (接口类型mPrivateFlagsandroid体系 & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT;
final boolean specChanged = widthMeasureSpec != mandroid下载安装OldWapproachidthMeasureSpec
|| heightMeasureSpec != mOldHeightMeasureSpec;
fi变量英文nal boolean isSpecExactly = MeasureSpec.getMode(widthandroid下载MeasureSpec) == MeasureSpec.EXACTLY
&& MeasureSpec.g接口无权限是什么意思etModeapprove(heightMeasureSpec) == MeasureSpecanvasesc.EXACTLY;
final boolean matchesSpecSize = getMeasuredWidth() ==canvases MeasureSpec.getSize(widthMeasureSpec)
&& getMeasuredHeight() == MeasureSpec.getSize(heightMeasurappearanceeSpec);
final boolean needsLayapp下载out = specChanged
&&aandroid什么意思mp; (sAlwaysRemeasureExactly || !isSpandroid下载ecExactapprovely || !matchesSpecSize);
// 需求从头布局  
if (forceLayout || needsLayout) {
. . .
// 先尝试从缓从中获取,若forceLayout为t接口crc过错计数rue或是缓存中不存在或是
// 忽略缓存,则调用onMeasure()从头进行丈量作业
int cacheIndex = forceLayout ? -1 : m接口crc过错计数MeasureCache.indexOfKey(key);
if (cacheIndex < 0 || sIgnoreMeasuappointmentreCache) {
// measure ou变量min表明什么类型的变量rselves, this should set the measured dimension flag back
onMeandroid的drawable类asure(widthMeasureSpandroid是什么手机牌子ec, heightCanvasMeasureSpec);
. . .
} else {canvas交大
// 缓存射中,直接从缓存中取值即可,不用再丈量
long value = mMeasureCache.valueAt(cacheIndex);
// Casting a loapp下载ng to int drops the high 32 bits, no mask needed
setMeasuredDimens接口ionRaw((int) (value >> 32), (int) value);
. . .
}
. . .
}
mOldWidthMeasureSpec = widthMeasureSpec;
mOldHeightMeasu接口卡reSpec = heightMeasureSpec;
mMeasureCa变量英文che.put(android的drawable类key, ((long) mMeasuredWidthandroid体系) << 32 |
(long) mMeasuredHeight & 0xffffffffL); // suppress sign extension
}

从measure()办法的源码中咱们能够知道,只需以下两种情况之一,才会进行实践的丈量作业:

  • foappearrceLayout为true : 这表明强制apple从头布局,能够经过View.接口卡requestLayout()来结束
  • needsLayout为true : 这需求specChanged为true(表明本次传入的MeasureSpec与前次传入的不同),并且以下3个条件有一个建立
  • sAlwaysR接口emeasureExactly为true: 该变量默以为false;
  • isSpeandroid什么意思cExactly为false: 若父View对子View提出了精确的宽高捆绑,则该变量为true,否则为false
  • matchesSpecSize为false: 表明父Viappearanceew的宽高规范要求与前次丈量的成果不同

对于decorView来说,实践实行丈量作业的是FrameLayout的onMea接口无权限是什么意思sure()办法,该办法的源码如下:

@Override
protected void onMeasuapprovere(int widtapplicationhMeasureAndroidSpec, iCanvasnt heightMeaAPPsureSpec) {
int count = getandroid下载安装ChildCount()接口卡;
. . .
int maxHeight = 0;
int maxWidth = 0;
int childState = 0;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (mMeasureAllChildren ||approach child.gandroid的drawable类etVisibilityappearance() != GONE) {
measureChildWithMargins(child, wi接口crc过错计数dcanvas下载thMeasureSpec, 0, heightMea接口无权限是什么意思sureSpec, 0);
final LayoutParams lp = (LayoutParams) child.ge接口自动化tLayoutParamapproves();
maxWidth = Math.max(maxWiCanvasdth,
child.getMeasuredWidth() + lp.leftMar接口无权限gin + lp.rightMargin);
maxHeight = Math.max(maxHeight,
child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
childState = com接口crc过错计数bineMeasuredStatesappointment(childState, child.getMeasuredState());
. . .
}
}
//接口自动化 Account for padding tooappreciate
maxWidth += getPaddcanvasesingLeftWithForeground() + getPaddingRig接口测验面试题htWithForcanvas什么意思eground();canvas3
maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForecanvasesground();
// Check against our minimum height and width
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
maxWidthappointment = Math.max(maxWidth, getSuggestedMinimumWidth());
// Check against our foreground's minimum height and width
final Drawable drawable = getForeground();
if (drawable !=接口无权限是什么意思 null) {
maxHeight = Mat变量与函数h.max(maxHeight, drawable.ge接口无权限tMinimumHeight());
maxWidth = Math.max(maxWicanvas翻译dth, dracanvas3wable.getMinimumWidth());
}
setMeasuredD变量imension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
resolveSizeAndState(maxHeapproachight, heicanvas什么意思ghtMeasureSpec,
childState << MEASURED_HEIGHT_STATE_SHIFT));
. . .
}

View的measu变量类型有哪些re进程

Android View的制作进程温习小结

在单一View的丈量进程中实践首先android的drawable类要效android下载安装果的办法有canvas教程两个:
getDefaultSize():获取Viewandroid手机的实践丈量宽高;
setMeasuredDimension():存储View的实践测Canvas量宽高;

ViewGroup的measure进程

Android View的制作进程温习小结

ViewGroup的丈量进程除了结束自身的丈量之canvas翻译外,还会遍历去调用子View的android什么意思measure()办法。ViewGroup是一个抽象类,没有重写View的onMea接口surappeare()办法,所以需appstore求子类去结束onMeasure()办法规则详细的丈量规则。

ViewGroup子类复写onMeasure()办法有3个进程:

  • 遍历悉数子Vieappearw并丈量其宽高 , 直接口卡接调用ViewGr接口卡oup的meandroid电子市场asureChildrapplicationen()办法
  • 兼并核算悉数子view的宽高,毕竟得到父view的丈量宽高
  • 存储父View的宽高

ViewGroup中供给了**measureChildren()办法,该办法首canvas下载要遍历悉数的子View并调用其measureChild()**办法.

在ActiviAndroidty启动时,怎么正确获取一个View的宽高:由于View的measure进程approach和Activity的生命周期是不同步的,所以无法确保Activity的onCreate()或许onResume()办法实app下载行时某个canvasesView现已丈量结束,app下载能够经过以下办法来处理:
(1app下载)在onWindowFocusCha接口crc过错计数nged()办法中获取View的宽高,该办法可能会被一再调用;
(2)经过ViewTreeObserver的OnGlobalLayoutListener监听接口Android当View树的情况产生改动或许View树内部的View的可见接口性产生改动时,就会回调onGlobalLayout()办法,在该办法中能够精确获取View的实践宽高.

Layout进程

View的Laappreciateyout进程首要是供认View的四个极点方位,然后供认其在容器中的方位,详细的layout进程和measure进程大致相似。

1、View的layout进程

Android View的制作进程温习小结

对于单一View的layout进程,首要调用View的layout()办法,在该办法中经过setFrame()办法来设定View的四个极点的方位,即 初始化mLeft、mTop、mRight、mBottom这四个值,View的四个极点一旦供认,那么View在父容器的方位也就供认了。接着canvas3会调用**onLayout()**办法供认悉数子View在父容器中的方位,由于是appearance单一View的layout进程,所以 onLayout()办法为空结束,由于没有子View(如果是ViewGroup需求变量子类结束 onLayout()办法)。

2、V接口iewGroup的layout进程

Android View的制作进程温习小结

ViewGroup的layout进程首要会调用自身canvas下载layout()办法,但和View的layout进程不相同的是,ViewGroup需求子类结束onLayout()办法,循环遍历悉数的子View并调用其layout()办法供认子View的方位,然后毕竟供认Vicanvas标签ewGroup在父容器的方位。

在onLayout()中首要遍历悉数子View并调用setChildFrame(),在setChildFrame()中调用子View的layout()来供认每个子View的方位,然后毕竟供认自身的方位。

draw进程

Drcanvas翻译aw进程首要是制作Vicanvas3ew的进程,也分为单一View的制作和ViewGroup的制作。

View的dra变量提高w进程都是从调用draw()办法开端的,该办法首android下载安装要结束如下作业流程:

(1) drawBackground():制作布景;

(2变量是什么意思) 保存当时的canvas层(不是必须的);

(3) onDraw(): 制作View的内容,这是一个空结束,需求子View根据要制作的颜色、线条等样式去详细结束,所以要在子View里重写该办法;

(4) dispatchDraw(): 对悉数子View进行制作;单一View的dispatchDraw()办法是一个空办法,由于canvas下载单一View没有子View,变量英文不需求结束dispatchDraw ()办法,而ViewGroup就不相同了canvas交大,它结束了dispatchDraw()办法去遍历悉数子V变量名的命名规则iew进行制作;

(5) onDrawForeground():制作装修,比方滚动条.

1、View的draw进程

Android View的制作进程温习小结

2、ViewGroup的draw进程

Android View的制作进程温习小结

draw两个简略混杂的办法,两canvas下载者都是改写View的办法:

invalidate(): 不会经过measure和layout进程,只会调用draw进程;

requestLayout() :会调用measure和layout进程从头丈量巨细和供认方位,不接口crc过错计数会调用draw进程;

所以当我变量泵们进行View更新时,若仅View的闪现内容产生改动且新闪现内容不影响View的巨细、方位,则只需调用invalidate办法;若View宽高、方位产生改动且闪现内容不变,只需调用requestLayout办法;若两者均产生改动,则需调用两者,按照View的制作流程,举荐先调用canvas翻译requestLayout办法再apple调用invalidate办法。

发表评论

提供最优质的资源集合

立即查看 了解详情