Android9.0 View的绘制源码解析(二)

一.开始

上篇文章我们已经分析到在performTraversals中,View的performMeasure(),performLayout(),performDraw()方法顺序执行,那我们来详细的看下它们是怎么执行的。

二.performMeasure解析

在ViewRootImpl中,performMeasure是实现为

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

                    if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed!  mWidth="
                            + mWidth + " measuredWidth=" + host.getMeasuredWidth()
                            + " mHeight=" + mHeight
                            + " measuredHeight=" + host.getMeasuredHeight()
                            + " dispatchApplyInsets=" + dispatchApplyInsets);

                     // Ask host how big it wants to be
                    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);

传入的参数childWidthMeasureSpec,childHeightMeasureSpec为根View,也就是mDecorView的测试参数,我们看下其实现

  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;
    }

当匹配父容器时,测试模式为MeasureSpec.EXACTLY,大小为屏幕大小

当包裹父容器时,测量模式为MeasureSpec.AT_MOST,大小为屏幕大小

当为其它情况时,测试模式为MeasureSpec.EXACTLY,大小为mDecorView设置的大小

因为mDecorView为MeasureSpec.EXACTLY,所以我们的Activity默认是屏幕大小

看下makeMeasureSpec的实现

  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);
            }
        }

通过测量大小和测量模式,组合成了mDecorView的测量规格,mDecorView的测量结束后,我们看下其performMeasure的实现

 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);
        }
    }

继续看下View的measure的实现

public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
        ...
        if (forceLayout || needsLayout) {
            // first clears the measured dimension flag
            mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;

            resolveRtlPropertiesIfNeeded();

            int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key);
            if (cacheIndex < 0 || sIgnoreMeasureCache) {
                // measure ourselves, this should set the measured dimension flag back
                onMeasure(widthMeasureSpec, heightMeasureSpec);
                mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
            } else {
                long value = mMeasureCache.valueAt(cacheIndex);
                // Casting a long to int drops the high 32 bits, no mask needed
                setMeasuredDimensionRaw((int) (value >> 32), (int) value);
                mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
            }
            ...
    }

在需要测量的条件满足下,会调用onMeasure(widthMeasureSpec, heightMeasureSpec);我们看下其实现

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

最终setMeasuredDimension传入了测量的宽高。当然顶层mDecorView的实现是一个FrameLayout,其实现了自己的onMeasure方法,这里就不再分析了。

三.performLayout解析

 在ViewRootImpl,调用是

performLayout(lp, mWidth, mHeight);

看其方法的实现

 private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
                               int desiredWindowHeight) {
        ...
        final View host = mView;
        ...
        try {
            host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
        }
    }

host即为View,看下View的layout的实现

   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);
}
}

其中调用了onLayout方法,看下其实现

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    }

看到原生的View中onLayout是空实现,具体实现由其实现View实现。

四.performDraw解析

ViewRootImpl的performDraw的实现是

    private void performDraw() {
...
            boolean canUseAsync = draw(fullRedrawNeeded);


}

draw的实现是

    private boolean draw(boolean fullRedrawNeeded) {
...
mAttachInfo.mTreeObserver.dispatchOnDraw();
}

其实现是ViewTreeObserver的dispatchOnDraw方法,看其实现

 public final void dispatchOnDraw() {
        if (mOnDrawListeners != null) {
            mInDispatchOnDraw = true;
            final ArrayList<OnDrawListener> listeners = mOnDrawListeners;
            int numListeners = listeners.size();
            for (int i = 0; i < numListeners; ++i) {
                listeners.get(i).onDraw();
            }
            mInDispatchOnDraw = false;
        }
    }

最终调用了mDeverView的onDraw方法。

Android9.0 View的绘制源码解析(一)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值