Android源码_View启动的measure、layout、draw

1,已知内容

1,Activity加载View的流程,首先创建出DecorView

2,由ViewRootImpl依次调用DecorView的measure、layout、draw方法

可参考:Android源码_Activity加载View

2,提问

1,measure、layout、draw功能的输入、输出有哪些?

2,measure、layout、draw功能的执行顺序(父与子之间)怎样?

3,DecorView的层次结构

1,DecorView是通过一系列的继承来实现功能的,而ViewRootImpl直接调用对象是DecorView。

2,列出DecorView继承的类的api,"×"代表该方法未被实现或是一个空方法

4-1,measure

ViewRootImpl调用部分

#ViewRootImpl.java,这里面的内容是零散的
{
	Rect frame = mWinFrame; // frame given by window manager.

	mWidth = frame.width();
	mHeight = frame.height();
	
	int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
    int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
	
	performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
}

#ViewRootImpl.java
    private static int getRootMeasureSpec(int windowSize, int rootDimension) {
        int measureSpec;
        switch (rootDimension) {
			case ViewGroup.LayoutParams.MATCH_PARENT:
				measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
				break;
			case ViewGroup.LayoutParams.WRAP_CONTENT:
				measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
				break;
			default:
				measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
				break;
			}
        return measureSpec;
    }

#View.java$$MeasureSpec内部类
	public static int makeMeasureSpec(int size, int mode) {
		if (sUseBrokenMakeMeasureSpec) { // 版本号小于等于17 为 true,否则为 false
			return size + mode;
		} else {
			return (size & ~MODE_MASK) | (mode & MODE_MASK);
		}
	}

#ViewRootImpl.java
    private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
        ...
        mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        ...
    }

1,输出参数为屏幕的宽、高,加上Match_Parent和Wrap_Parent的标记量

DecorView的循环调用部分

#View.java
	public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
        ...
        if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2);
		
		...
		int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :
				mMeasureCache.indexOfKey(key);
		if (cacheIndex < 0 || sIgnoreMeasureCache) {
			onMeasure(widthMeasureSpec, heightMeasureSpec);
		} else {
			long value = mMeasureCache.valueAt(cacheIndex);
			setMeasuredDimensionRaw((int) (value >> 32), (int) value);
		}

		...
        mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 |
                (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension
    }

#DecorView.java
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		...
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		
		...
		if (measure) {
			super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		}
	}
	
#FrameLayout.java
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int count = getChildCount();

        mMatchParentChildren.clear();

        int maxHeight = 0;
        int maxWidth = 0;
        int childState = 0;

        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (mMeasureAllChildren || child.getVisibility() != GONE) {
                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);
                
				...
				if (lp.width == LayoutParams.MATCH_PARENT ||
						lp.height == LayoutParams.MATCH_PARENT) {
					mMatchParentChildren.add(child);
				}
            }
        }

        ...
        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
                resolveSizeAndState(maxHeight, heightMeasureSpec,
                        childState << MEASURED_HEIGHT_STATE_SHIFT));

        count = mMatchParentChildren.size();
        if (count > 1) {
            for (int i = 0; i < count; i++) {
                ...
                child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
            }
        }
    }

#ViewGroup.java
    protected void measureChildWithMargins(View child,
            int parentWidthMeasureSpec, int widthUsed,
            int parentHeightMeasureSpec, int heightUsed) {
        ...
        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }
	
#View.java
    protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
        ...
        setMeasuredDimensionRaw(measuredWidth, measuredHeight);
    }

#View.java
    private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {
        mMeasuredWidth = measuredWidth;
        mMeasuredHeight = measuredHeight;

        mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
    }

父子调用顺序:View.measure -> DecorView.onMeasure -> FrameLayout.onMeasure -> ViewGroup.measureChildWithMargins -> 新的循环【实际操作的View都是DecorView】

单个View的逻辑:1,将子View计算出来;2,依据子View将父View计算出来;3,将某些需要父View信息的子View再次计算

最终的输出函数是:View.setMeasureDimensionRaw

输出内容为:mMeasureWidth、mMeasureHeight、mPrivateFlags

所以measure最终目的就是,将DecorView下所有子View的宽和高计算出来

4-2,layout

ViewRootImpl调用部分

#ViewRootImpl.java,这里面的内容是零散的
{
	Rect frame = mWinFrame; // frame given by window manager.

	desiredWindowWidth = frame.width();
	desiredWindowHeight = frame.height();
			
	performLayout(lp, desiredWindowWidth, desiredWindowHeight);
}

#ViewRootImpl.java
    private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
            int desiredWindowHeight) {
        ...
        host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
		...
    }

输入参数为:屏幕的宽、高

DecorView的循环调用部分

#ViewGroup.java
    public final void layout(int l, int t, int r, int b) {
        ...
        super.layout(l, t, r, b);
        ...
    }

#View.java
    public void layout(int l, int t, int r, int b) {
        ...
        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);
            ...
        }
        ...
    }
#View.java
	private boolean setOpticalFrame(int left, int top, int right, int bottom) {
        ...
        return setFrame(
                left   + parentInsets.left - childInsets.left,
                top    + parentInsets.top  - childInsets.top,
                right  + parentInsets.left + childInsets.right,
                bottom + parentInsets.top  + childInsets.bottom);
    }
#View.java
    protected boolean setFrame(int left, int top, int right, int bottom) {
        ...
        if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {
            ...
            mLeft = left;
            mTop = top;
            mRight = right;
            mBottom = bottom;
            ...
        }
        ...
    }

#DecorView.java
	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
		super.onLayout(changed, left, top, right, bottom);
		...
	}

#FrameLayout.java
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        layoutChildren(left, top, right, bottom, false /* no force left gravity */);
    }

#FrameLayout.java
    void layoutChildren(int left, int top, int right, int bottom,
                                  boolean forceLeftGravity) {
        ...
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                ...
                child.layout(childLeft, childTop, childLeft + width, childTop + height);
            }
        }
    }

父子调用顺序:ViewGroup.layout -> View.layout -> DecorView.onLayout -> FrameLayout.onLayout -> FrameLayout.layoutChildren -> 新的循环【实际操作的View都是DecorView】

单个View的逻辑:1,将父View的定位计算出来;2,利用父View将子View的定位计算出来

最终的输出函数是:View.setFrame

输出内容为:mLeft、mTop、mRight、mBottom

所以layout最终目的就是,将DecorView下所有子View的位置计算出来。这里也可以看出,mWidth和mMeasureWidth是在不同时期计算出来内容

4-3,draw

ViewRootImpl调用部分

#ViewRootImpl.java
	private void performDraw() {
        ...
        draw(fullRedrawNeeded);
		...
    }
#ViewRootImpl.java
    private void draw(boolean fullRedrawNeeded) {
        ...
        drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)
        ...
    }
#ViewRootImpl.java
    private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
            boolean scalingRequired, Rect dirty) {

        final Canvas canvas;
        try {
			...
            canvas = mSurface.lockCanvas(dirty);
			...
        } 
		...

        try {
            ...
            mView.draw(canvas);
			...
        } finally {
			...
            surface.unlockCanvasAndPost(canvas);
			...
        }
        return true;
    }

surface lock状态下的canvas

DecorView的循环调用部分

#DecorView.java
	public void draw(Canvas canvas) {
		super.draw(canvas);

		if (mMenuBackground != null) {
			mMenuBackground.draw(canvas);
		}
	}
	
#View.java
    public void draw(Canvas canvas) {
        final int privateFlags = mPrivateFlags;
        final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
                (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
        mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;

        /*
         * Draw traversal performs several drawing steps which must be executed
         * in the appropriate order:
         *
         *      1. Draw the background
         *      2. If necessary, save the canvas' layers to prepare for fading
         *      3. Draw view's content
         *      4. Draw children
         *      5. If necessary, draw the fading edges and restore layers
         *      6. Draw decorations (scrollbars for instance)
         */

        // Step 1, draw the background, if needed
        if (!dirtyOpaque) {
            drawBackground(canvas);
        }
		
		...
        // Step 2, save the canvas' layers
        int solidColor = getSolidColor();
        if (solidColor == 0) {
            final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;

            if (drawTop) {
                canvas.saveLayer(left, top, right, top + length, null, flags);
            }

            if (drawBottom) {
                canvas.saveLayer(left, bottom - length, right, bottom, null, flags);
            }

            if (drawLeft) {
                canvas.saveLayer(left, top, left + length, bottom, null, flags);
            }

            if (drawRight) {
                canvas.saveLayer(right - length, top, right, bottom, null, flags);
            }
        }
		
		...
        // Step 3, draw the content
        if (!dirtyOpaque) onDraw(canvas);
		
		...
        // Step 4, draw the children
        dispatchDraw(canvas);

        // Step 5, draw the fade effect and restore layers
        final Paint p = scrollabilityCache.paint;
        final Matrix matrix = scrollabilityCache.matrix;
        final Shader fade = scrollabilityCache.shader;

        if (drawTop) {
            matrix.setScale(1, fadeHeight * topFadeStrength);
            matrix.postTranslate(left, top);
            fade.setLocalMatrix(matrix);
            p.setShader(fade);
            canvas.drawRect(left, top, right, top + length, p);
        }

        if (drawBottom) {
            matrix.setScale(1, fadeHeight * bottomFadeStrength);
            matrix.postRotate(180);
            matrix.postTranslate(left, bottom);
            fade.setLocalMatrix(matrix);
            p.setShader(fade);
            canvas.drawRect(left, bottom - length, right, bottom, p);
        }

        if (drawLeft) {
            matrix.setScale(1, fadeHeight * leftFadeStrength);
            matrix.postRotate(-90);
            matrix.postTranslate(left, top);
            fade.setLocalMatrix(matrix);
            p.setShader(fade);
            canvas.drawRect(left, top, left + length, bottom, p);
        }

        if (drawRight) {
            matrix.setScale(1, fadeHeight * rightFadeStrength);
            matrix.postRotate(90);
            matrix.postTranslate(right, top);
            fade.setLocalMatrix(matrix);
            p.setShader(fade);
            canvas.drawRect(right - length, top, right, bottom, p);
        }

        canvas.restoreToCount(saveCount);

        // Overlay is part of the content and draws beneath Foreground
        if (mOverlay != null && !mOverlay.isEmpty()) {
            mOverlay.getOverlayView().dispatchDraw(canvas);
        }

        // Step 6, draw decorations (foreground, scrollbars)
        onDrawForeground(canvas);
    }
#ViewGroup.java
    protected void dispatchDraw(Canvas canvas) {
        ...
        for (int i = 0; i < childrenCount; i++) {
            while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) {
                final View transientChild = mTransientViews.get(transientIndex);
                if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
                        transientChild.getAnimation() != null) {
                    more |= drawChild(canvas, transientChild, drawingTime);
                }
                transientIndex++;
                if (transientIndex >= transientCount) {
                    transientIndex = -1;
                }
            }
            int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
            final View child = (preorderedList == null)
                    ? children[childIndex] : preorderedList.get(childIndex);
            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
                more |= drawChild(canvas, child, drawingTime);
            }
        }
		
		// 继续绘制
        while (transientIndex >= 0) {
            final View transientChild = mTransientViews.get(transientIndex);
            if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
                    transientChild.getAnimation() != null) {
                more |= drawChild(canvas, transientChild, drawingTime);
            }
            transientIndex++;
            if (transientIndex >= transientCount) {
                break;
            }
        }
		...
	}
#ViewGroup.java
    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
        return child.draw(canvas, this, drawingTime);
    }
	
#DecorView.java
	public void onDraw(Canvas c) {
		super.onDraw(c);
		mBackgroundFallback.draw(mContentRoot, c, mContentParent);
	}

父子调用顺序:DecorView.draw-> View.draw-> ViewGroup.dispatchDraw-> ViewGroup.drawChild -> 新的循环【实际操作的View都是DecorView】

单个View的逻辑:"父View背景" -> "父View内容" -> "子View" -> "父View foreground、scrollbar" -> 新的循环

最终的输出函数是:略【都是对canvas直接操作】

输出内容为:canvas上绘制的内容

所以draw最终目的就是,利用measure和layout中计算出的内容,将内容显示给用户

 

5,回答提问

  输入 输出 执行顺序
measure 屏幕宽高 + 标记

mMeasureWidth

mMeasureHeight

"子View" -> "父view" -> "某些需要父类信息的View" -> 新的循环
layout 屏幕宽高 mLeft、mRight、mTop、mButtom "父View" -> "子View" -> 新的循环
draw canvas canvas上的"装饰" "父View背景" -> "父View内容" -> "子View" -> "父View foreground、scrollbar" -> 新的循环

 

 

 

 

 

 

 

 

 

 

ylineSign

QQ群:644213963

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章