前言

一个View,从无到有会走三个流程,也就是陈词滥调的measure,layout,draw三流程;

咱们都晓得Android视图是由一层一层形成的层级构造,直白点说,就是父View蕴含子View而子View又能够蕴含子View。所以绘制流程是由最外层的View开始,一步一步向内传递执行。而整个过程又是递归期待的,最外层的View须要等内层所有的View执行完绘制流程才完结,所以便有了”缩小布局层级,能够无效晋升App性能”这一经典总结。

注释

什么时候开始绘制?

而万物有始才有终,你不惹他,他也不会入手打你。View的绘制流程是什么时候开始的?谁触发的?明确这点后,才去思考这个过程是怎么执行的。

咱们都分明Activity中onCreate()办法在setContentView()后,View的宽高是获取不到的。同时咱们晓得Activity在onResume()后才齐全可见,并且首次在onResume()办法中也是拿不到View的尺寸的,这样能够推算得出:View的绘制流程是在onResume()办法执行完结后才开始的。那Activity的生命周期办法背地是由谁,又何时调用的?

答:ActivityManagerService 

ActivityManagerService(以下简称AMS))是Androids下层零碎中最外围的服务之一,次要负责零碎中四大组件的启动、切换、调度及应用程序的治理和调度等工作。具体具体内容参考以下地址:

https://blog.csdn.net/gaugame...

相对而言ActivityThread的main办法是应用程序的入口,main()办法里做一些初始化工作,其中包含和AMS建设起通信。

public class ActivityThread{    final ApplicationThread mAppThread = new ApplicationThread();    final Looper mLooper = Looper.myLooper();    final H mH = new H();    final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();    public static void main(String[] args) {        //初始化lopper        Looper.prepareMainLooper();        //初始化ActivityThread        ActivityThread thread = new ActivityThread();        //ApplicationThread和AMS建立联系        thread.attach(false);        //取音讯        Looper.loop();        //loop()办法如果执行完结,未能取到音讯,程序抛出异样退出。        throw new RuntimeException("Main thread loop unexpectedly exited");    }}

ActivityThread会治理和用户打交道的Activity,利用所有的Activity都存在ActivityThread中的mActivities汇合中,而ActivityThread响应AMS的号召,须要借助ApplicationThread来承受这个诏令,点进去看全都是生命周期办法。接着调用attach()办法让ApplicationThread和AMS建立联系。H类就是一个Handler类,用于发送生命周期扭转的音讯,告诉响应操作。

private class ApplicationThread extends IApplicationThread.Stub {    //告诉相应的过程执行启动Activity的操作    public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,            ActivityInfo info, Configuration curConfig, Configuration overrideConfig,            CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,            int procState, Bundle state, PersistableBundle persistentState,            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,            boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {        sendMessage(H.LAUNCH_ACTIVITY, r);    }    public final void scheduleResumeActivity(IBinder token, int processState,            boolean isForward, Bundle resumeArgs) {        sendMessage(H.RESUME_ACTIVITY, token, isForward ? 1 : 0, 0, seq);    }    //.....}

对于AMS我也不太懂在这儿提一下明确是怎么回事就行,当前再缓缓钻研。当Activity启动时会先调用到scheduleLaunchActivity()办法,由Handler发送告诉音讯后执行handleLaunchActivity()->performLaunchActivity()->callActivityOnCreate()->Activity.onCreate()。

private class H extends Handler {    public void handleMessage(Message msg) {        switch (msg.what) {            case LAUNCH_ACTIVITY: {                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");                final ActivityClientRecord r = (ActivityClientRecord) msg.obj;                r.packageInfo = getPackageInfoNoCheck(                        r.activityInfo.applicationInfo, r.compatInfo);                //该办法中会执行Activity的onCreate()办法。                handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);            } break;            //onResume();             case RESUME_ACTIVITY:                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume");                SomeArgs args = (SomeArgs) msg.obj;                handleResumeActivity((IBinder) args.arg1, true, args.argi1 != 0, true,                        args.argi3, "RESUME_ACTIVITY");                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);                break;        }    }}final void handleResumeActivity(IBinder token,            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {        ActivityClientRecord r = mActivities.get(token);    //.............    //执行onResume()办法    r = performResumeActivity(token, clearHide, reason);     if (r != null) {        final Activity a = r.activity;         if (r.window == null && !a.mFinished && willBeVisible) {                r.window = r.activity.getWindow();                View decor = r.window.getDecorView();                decor.setVisibility(View.INVISIBLE);                ViewManager wm = a.getWindowManager();                WindowManager.LayoutParams l = r.window.getAttributes();                a.mDecor = decor;            if (a.mVisibleFromClient) {                if (!a.mWindowAdded) {                    a.mWindowAdded = true;                    //将DecorView增加到Window上                    wm.addView(decor, l);            }         }    //说法二:执行makeVisible()来增加View,但也是增加到Window里和下面一样的操作。分明的小伙伴能够通知我下。    if (r.activity.mVisibleFromClient) {            r.activity.makeVisible();        }    }}

onResume()时也一样,当Activity的状态产生扭转,通过层层调用执行到handleResumeActivity()办法,在办法中先调用Activity.onResume()办法,再执行WindowManager的addView()办法将Activity的根View(DecorView)增加下来,进而开始绘制流程。这就解释了为什么首次在onResume()办法中获取不到View的宽高。对DecorView不太明确的能够参考Activity中setContentView浅析。地址如下所示:

https://blog.csdn.net/sinat_3...

而WindowManager实现类为WindowManagerImpl,WindowManagerImpl中addView()办法又会调用WindowManagerGlobal的addView()办法。参考如下:

https://www.jianshu.com/p/c22...
 public void addView(View view, ViewGroup.LayoutParams params,            Display display, Window parentWindow) {    ······    root = new ViewRootImpl(view.getContext(), display);    view.setLayoutParams(wparams);    mViews.add(view);    mRoots.add(root);    mParams.add(wparams);    //行将开始流程绘制        root.setView(view, wparams, panelParentView);    ·······}

addView()办法中先创立ViewRootImpl对象,随后执行setView()办法将其和DecorView绑定起来,绘制流程也将由ViewRootImpl()来执行。setView()办法中会执行requestLayout()办法。

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {     if (mView == null) {        mView = view;         // Schedule the first layout -before- adding to the window         // manager, to make sure we do the relayout before receiving         // any other events from the system.         requestLayout();    }}

requestLayout()办法走上来会异步执行performTraversals()办法,View的三大流程都是在该办法中执行的。到这儿咱们算是明确View的绘制流程是从哪儿开始的,接下来剖析这个过程到底是怎么做的。

private void performTraversals() {    //计算DecorView根View的MeasureSpec    int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);    int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);    performLayout(lp, mWidth, mHeight);    performDraw();}

measure流程

说到measure流程就不得提到一个类,MeausreSpec。应用该类用一个int值就能记录View测量的宽高和宽高的测量模式,大大节约开销。

public static class MeasureSpec {    private static final int MODE_SHIFT = 30;    //int类型占4个字节,1个字节=8bit(位)。    private static final int MODE_MASK  = 0x3 << MODE_SHIFT; //11000000000000000000000000000000    public static final int UNSPECIFIED = 0 << MODE_SHIFT; //00000000000000000000000000000000  据说用于零碎外部,想要多大就给多大。平时也没有用到过,上面不做剖析。    public static final int EXACTLY     = 1 << MODE_SHIFT; //01000000000000000000000000000000  准确值模式,对应LayoutParams的match_parent或者固定尺寸    public static final int AT_MOST     = 2 << MODE_SHIFT; //10000000000000000000000000000000  最大值模式,对应LayoutParams的wrap_content     public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,                                          @MeasureSpecMode int mode) {        if (sUseBrokenMakeMeasureSpec) {            return size + mode;        } else {            return (size & ~MODE_MASK) | (mode & MODE_MASK);        }    }    public static int getMode(int measureSpec) {            return (measureSpec & MODE_MASK);    }    public static int getSize(int measureSpec) {        return (measureSpec & ~MODE_MASK);    }}

用一句话解释MeasureSepc:

用位运算的形式来”压缩”记录View的测量宽高和测量模式,其中高(前)两位代表测量模式后三十位代表测量后的尺寸。同时提供”解压”的办法转为咱们须要的理论数值。

MeasureSpec = MeasureMode+MeasureSize

咱们以int mMeausreWidth = makeMeasureSepc(720,MeasureSpec.EXACTLY)为例: 

getMode亦是如此

//生成DecorView根View的MeasureSpecint childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);

measure流程开始执行之前,会先计算出DecorView的MeasureSpec。此处mWidth和mHeight就为屏幕的宽高,LayoutParmas都为match_parent。

private static int getRootMeasureSpec(int windowSize, int rootDimension) {    int measureSpec;    switch (rootDimension) {    case ViewGroup.LayoutParams.MATCH_PARENT:        // Window can't resize. Force root view to be windowSize.        measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);        break;    case ViewGroup.LayoutParams.WRAP_CONTENT:        // Window can resize. Set max size for root view.        measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);        break;    default:        // Window wants to be an exact size. Force root view to be that size.        measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);        break;    }    return measureSpec;}

计算出DecorView的MeasureSpec后,执行DecorView的measure()办法开始整个View树的测量。

private void performMeasure()(int childWidthMeasureSpec, int childHeightMeasureSpec) {    if (mView == null) {        return;    }    Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");    try {        mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);    } finally {        Trace.traceEnd(Trace.TRACE_TAG_VIEW);    }}

measure()办法是被final润饰了的,派生类都不能重写,所有View都会执行到View类的measure()办法。

public final void measure(int widthMeasureSpec, int heightMeasureSpec) {     onMeasure(widthMeasureSpec, heightMeasureSpec);}

onMeasure()办法意在二种:绝对于ViewGroup来说 

  1. 测量出子View的MeasureSpec后,再执行子View的measure流程 
  2. 给本人mMeasureWidth&Height赋值。 

View的onMeasure()办法就只干第二件事。咱们以下xml布局为例,当咱们调用setContentView(R.layout.activity_main)后:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="horizontal"    tools:context=".MainActivity">    <TextView        android:layout_height="wrap_content"        android:layout_height="wrap_content"        android:text="Hello World"/></LinearLayout>

此时此处DecorView有实现onMeausre办法并且会执行父类FrameLayout的onMeausre()办法。

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    for (int i = 0; i < count; i++) {        final View child = getChildAt(i);        if (mMeasureAllChildren || child.getVisibility() != GONE) {            //core            measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);            final LayoutParams lp = (LayoutParams) child.getLayoutParams();            maxWidth = Math.max(maxWidth,child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);            maxHeight = Math.max(maxHeight,child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);            childState = combineMeasuredStates(childState, child.getMeasuredState());            if (measureMatchParentChildren) {                if (lp.width == LayoutParams.MATCH_PARENT ||                        lp.height == LayoutParams.MATCH_PARENT) {                    mMatchParentChildren.add(child);                }            }        }    }    //设置的前景    maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground();    maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground();    maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());    maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());    //设置的background    final Drawable drawable = getForeground();    if (drawable != null) {    maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());    maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());    }    //给本人的mMeasuredWidth和mMeasuredHeight赋值    setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),resolveSizeAndState(maxHeight, heightMeasureSpec,childState <<MEASURED_HEIGHT_STATE_SHIFT));}SizeAndState(maxHeight, heightMeasureSpec,childState <<MEASURED_HEIGHT_STATE_SHIFT));}

onMeasure()办法中遍历所有子View,通过执行measureChildWithMargins()办法,先计算出子View的MeasureSpec再调用子View的measure()办法传递执行measure流程。

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);    //开始LinearLayout的measure流程    child.measure(childWidthMeasureSpec, childHeightMeasureSpec);}a

父View在帮忙计算子View的MeasureSpec时有着固定的套路: 

  1. 受父View的MeasureSpec影响 
  2. 受子View本身的LayoutParams影响 
  3. 计算父View剩下可用的区域,减去父View的padding和子View的margin间隔和父View曾经应用(预约)的区域大小。
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {    //父View的宽/高测量模式    int specMode = MeasureSpec.getMode(spec);    //父View的宽/高大小    int specSize = MeasureSpec.getSize(spec);    //父View剩下的可用区域    int size = Math.max(0, specSize - padding);    int resultSize = 0;    int resultMode = 0;    switch (specMode) {    //父View_EXACTLY    case MeasureSpec.EXACTLY:        //如果子View写si了宽/高        if (childDimension >= 0) {            //子View的MeasureSpec=EXACTLY+写si的宽/高(si说多了不吉利)            resultSize = childDimension;            resultMode = MeasureSpec.EXACTLY;        } else if (childDimension == LayoutParams.MATCH_PARENT) {            //子View的MeasureSpec=EXACTLY+父View剩下的区域            resultSize = size;            resultMode = MeasureSpec.EXACTLY;        } else if (childDimension == LayoutParams.WRAP_CONTENT) {            resultSize = size;            resultMode = MeasureSpec.AT_MOST;        }        break;    //父View_AT_MOST    case MeasureSpec.AT_MOST:        //如果子View写死了宽高        if (childDimension >= 0) {            //子View的MeasureSpec=EXACTLY+写si的宽/高            resultSize = childDimension;            resultMode = MeasureSpec.EXACTLY;        } else if (childDimension == LayoutParams.MATCH_PARENT) {            //子View的MeasureSpec=AT_MOST+父View剩下的区域            resultSize = size;            resultMode = MeasureSpec.AT_MOST;        } else if (childDimension == LayoutParams.WRAP_CONTENT) {            resultSize = size;            resultMode = MeasureSpec.AT_MOST;        }        break;    //父View_UNSPECIFIED素来没有用到,不做剖析    case MeasureSpec.UNSPECIFIED:        if (childDimension >= 0) {            resultSize = childDimension;            resultMode = MeasureSpec.EXACTLY;        } else if (childDimension == LayoutParams.MATCH_PARENT) {            resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;            resultMode = MeasureSpec.UNSPECIFIED;        } else if (childDimension == LayoutParams.WRAP_CONTENT) {            resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;            resultMode = MeasureSpec.UNSPECIFIED;        }        break;    }    return MeasureSpec.makeMeasureSpec(resultSize, resultMode);}

getChildMeasureSpec()生产子View的MeasureSpec总结如下: 

  1. 子View写si宽高:测量模式不受父View影响,全都为EXACTLY,宽高为写si的宽高 
  2. 子View没有写si宽高:如果父View都为AT_MOST,子View想都别想还是为AT_MOST,如果父View为EXACTLY且子View的LayoutParams为match_parent,才为EXACTLY。宽高都为父View剩下的区域。这就很好的明确了为什么咱们自定义View时,如果没对View的宽高进行解决,View即便是wrap_content也会撑满整个屏幕了。
如果咱们写si的尺寸超过了无效范畴,比方超出了屏幕或者超过了父View的大小,最终的measureWidth/Height和理论宽高还是写死的尺寸,只不过超出的区域看不见而已。

ViewGroup在所有子View的measure流程都执行完结后,再调用setMeasuredDimension()办法给本人的mMeasureWidth/Height赋值。其实View在执行onMeausre()办法之前,曾经由父View(DecorView除外)计算出了一个无效的MeasureSpec,比方在执行performMeasure()办法之前就先一步计算出了DecorView的MeasureSpec,接着在measureChildWithMargins()办法中又先计算出LinearLayout的MeasureSpec,再执行LinearLayout的measure()流程。并且View最终的大小都不会超过这个范畴,即便呈现以下状况都是如此: 

  1. 在720-1280屏幕下,给View设置了一张1500-1500的图片 
  2. 子View的大小曾经超过了本人 

View最终的mMeasureWidth/Height,是由本身的测量模式,前/背景和子View的大小独特决定的。

setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),resolveSizeAndState(maxHeight, heightMeasureSpec,childState <<MEASURED_HEIGHT_STATE_SHIFT));public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {    final int specMode = MeasureSpec.getMode(measureSpec);    final int specSize = MeasureSpec.getSize(measureSpec);    switch (specMode) {        case MeasureSpec.AT_MOST:            if (specSize < size) {                result = specSize | MEASURED_STATE_TOO_SMALL;            } else {                result = size;            }            break;        case MeasureSpec.EXACTLY:            result = specSize;            break;        case MeasureSpec.UNSPECIFIED:        default:            result = size;    }    return result | (childMeasuredState & MEASURED_STATE_MASK);}
<com.example.yangjie.application.MyLinearLayout     xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/ll_test"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    tools:context=".MainActivity">@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    super.onMeasure(widthMeasureSpec, heightMeasureSpec);    Log.i("TAG","LinearLayoutWidth="+MeasureSpec.getSize(widthMeasureSpec));    Log.i("TAG","LinearLayoutHeight="+MeasureSpec.getSize(heightMeasureSpec));    Log.i("TAG","MeasureWidth="+getMeasuredWidth());}

当LinearLayout的LayoutParams时match_parent时好说,LinearLayout的MeasureMode为EXACTLY,size就是父View帮其计算出的MeasureSize。如果LinearLayout的LayoutParams为warp_content,在执行resolveSizeAndState()办法时会走到case MeasureSpec.AT_MOST:外面去。View最终的宽高会从本身的前/背景大小和子View的大小当选则一个最大值。在FrameLayout中会选出最大的子View的measureWidth/Height,因为FrameLayout的子View都是重叠放在左上角的,所以选出最大的那一个就行了。而LinearLayout会累计所有子View的大小。当然如果这个最大值超过了父View为其测量的MeasureSize,最终View的大小还是为父View为其测量的MeasureSize。specSize | MEASURED_STATE_TOO_SMALL;仅仅只是为了标记一个这个View的测量状态,在getMeasureWidth/Height()时值还是不变的。

ViewGroup的onMeausre()办法明确之后,再看View的就简略多了,给View的mMeasureWidth和Height赋值就行了。

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));}

如果咱们有给View设置background,getSuggestedMinimumWidth()会获取该大小,然而getDefaultSize()办法还是会抉择父View帮忙测量的MeasureSize。

public static int getDefaultSize(int size, int measureSpec) {    int result = size;    int specMode = MeasureSpec.getMode(measureSpec);    int specSize = MeasureSpec.getSize(measureSpec);    switch (specMode) {    case MeasureSpec.UNSPECIFIED:        result = size;        break;    case MeasureSpec.AT_MOST:    case MeasureSpec.EXACTLY:        result = specSize;        break;    }    return result;}

layout流程

绝对于measure流程而言,layout和draw流程就简略得多了,通过Layout流程来确定子View在父View中的地位。子View在父View中的地位,须要4个点来确定,同时也能够通过点的间隔来计算出View的大小。 

public final int getWidth() {    return mRight - mLeft;}public final int getHeight() {    return mBottom - mTop;}

performLayout办法中会执行DecorView的layout()办法来开始整个View树的layout流程。而DecorView包含其余的ViewGroup都没有另外实现layout()办法,都会执行到View的layout()办法。layout()办法中会先执行setFrme()办法确定View本人在父View中的地位,接着再执行onLayout()办法来遍历所有的子View,计算出子View在本人心中的地位(4个点)后,再执行子View的layout流程。不同的ViewGroup有着不同的形式来安顿子View在本人心中的地位。所以View类中的onLayout()是一个空办法,等着View们本人去实现。自定义ViewGroup的时候如果不在onLayout办法中安顿子View的地位,将看不见子View。

private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,int desiredWindowHeight) {    mLayoutRequested = false;    mScrollMayChange = true;    mInLayout = true;    final View host = mView;    host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());}public void layout(int l, int t, int r, int b) {    if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {        onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);        mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;    }    int oldL = mLeft;    int oldT = mTop;    int oldB = mBottom;    int oldR = mRight;    boolean changed = 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);    }}

laout流程,绝对于ViewGroup而言: 

  1. 确定本人在父View中的地位 
  2. 遍历所有子View,计算出在本人心中的地位(4个点)后,再执行子View的layout流程 

绝对于View(单个View)而言只干第一件事。

draw流程

performDraw()办法中会执行通过层层调用会执行到View的draw()办法。

private void performDraw() {    draw(fullRedrawNeeded);}private void draw(boolean fullRedrawNeeded) {    if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {                    return;    }}private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,boolean scalingRequired, Rect dirty) {    mView.draw(canvas);}public void draw(Canvas canvas) {    //绘制本人的背景    drawBackground(canvas);    //空实现,绘制本人的内容,自定义时重写该办法    onDraw(canvas)    //绘制子View    dispatchDraw(canvas);    //绘制前景    onDrawForeground(canvas);}

draw()办法会绘制一些本人的货色。通过dispatchDraw()办法来传递执行子View的draw流程。ViewGroup类中曾经实现:

protected void dispatchDraw(Canvas canvas) {    more |= drawChild(canvas, child, drawingTime);}

总结

View的绘制流程到此结束,有余反对多多包涵,指出独特探讨。

本文转自 【郭霖】 如有侵权,请分割删除。