View繪製流程

流程圖如下:


看高清圖請下載

對於開頭的方法是調用了ViewRootImpl方法裏的,之所以調這個方法也可通過高清圖進行分析這裏直接從performTraversals方法進行分析

    private void performTraversals() {
        // cache mView since it is used so much below...
        ......
            if (!mStopped || mReportNextDraw) {
               .....
                    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);

                   .......

                    if (measureAgain) {
                        if (DEBUG_LAYOUT) Log.v(mTag,
                                "And hey let's measure once more: width=" + width
                                + " height=" + height);
                        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
                    }

                    layoutRequested = true;
                }
            }
            .......

        
            performLayout(lp, mWidth, mHeight);

            ......

            performDraw();
            ......
    }

    private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
        try {
            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }
通過分析mView是DecorView,它實現繼承了VIew類因此查找measure的方法:

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

這個onMeasure實現在

   @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        ......

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        ......

        if (measure) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
查看方法可知調用了父類的onMeasure方法,DecorView也繼承FrameLayout類

 

  @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
	     ......

        count = mMatchParentChildren.size();
        if (count > 1) {
            for (int i = 0; i < count; i++) {
                final View child = mMatchParentChildren.get(i);
                ......
                child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
            }
        }
    }
通過遍歷的方式將子控件的大小計算出來,如果子控件還是VIewGroup將進行遞歸,也就是說計算控件的大小是通過遞歸遍歷的方式解決的

下面是Layout方法

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

            ......
            if (numViewsRequestingLayout > 0) {
              ......
                    host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());

			  ......

            }
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
        mInLayout = false;
    }
其中host就是DecorView,調用了父類View的方法
  public void layout(int l, int t, int r, int b) {
        ......

        if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
            onLayout(changed, l, t, r, b);
            mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;

            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnLayoutChangeListeners != null) {
                ArrayList<OnLayoutChangeListener> listenersCopy =
                        (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();
                int numListeners = listenersCopy.size();
                for (int i = 0; i < numListeners; ++i) {
                    listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
                }
            }
        }
		......
    }
這樣會調用Decor的onlayout方法如下:

  @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        ......
    }
調用了父類的onlayout方法:

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        layoutChildren(left, top, right, bottom, false /* no force left gravity */);
    }

 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);
            }
        }
    }
通過上面方法可知layout方法也是通過遞歸遍歷的方式來設置view的位置的,這個和計算view的大小的邏輯是一樣的

接下來是view的draw

  private void performDraw() {
        ......
        try {
            draw(fullRedrawNeeded);
        } finally {
            mIsDrawing = false;
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }

        ......
    }
  private void draw(boolean fullRedrawNeeded) {
        ......

                if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
                    return;
                }
            }
        }

        if (animating) {
            mFullRedrawNeeded = true;
            scheduleTraversals();
        }
    }
  private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
            boolean scalingRequired, Rect dirty) {

        ......
            try {
                canvas.translate(-xoff, -yoff);
                if (mTranslator != null) {
                    mTranslator.translateCanvas(canvas);
                }
                canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
                attachInfo.mSetIgnoreDirtyState = false;

                mView.draw(canvas);
				......
    }
其中的mView是DecorView控件,調用了View中的方法
  public void draw(Canvas canvas) {
        ......

        // Step 3, draw the content//繪製自己的內容
        if (!dirtyOpaque) onDraw(canvas);

        // Step 4, draw the children
        dispatchDraw(canvas);//繪製自己的子控件

        ......
    }
 @Override//調用的是ViewGroup中的
    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;
                }
            }

            final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
            final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
                more |= drawChild(canvas, child, drawingTime);
            }
        }
        while (transientIndex >= 0) {
            // there may be additional transient views after the normal views
            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;
            }
        }
        if (preorderedList != null) preorderedList.clear();

        // Draw any disappearing views that have animations
        if (mDisappearingChildren != null) {
            final ArrayList<View> disappearingChildren = mDisappearingChildren;
            final int disappearingCount = disappearingChildren.size() - 1;
            // Go backwards -- we may delete as animations finish
            for (int i = disappearingCount; i >= 0; i--) {
                final View child = disappearingChildren.get(i);
                more |= drawChild(canvas, child, drawingTime);
            }
        }
		......
    }
通過上面最終調用drawChild方法來進行繪製子控件
  protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
        return child.draw(canvas, this, drawingTime);
    }
draw這步也是通過遞歸遍歷的方式進行操作的。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章