View draw流程分析

作者: GrayMonkey | 来源:发表于2017-09-04 00:20 被阅读56次

    前言

    本文主要分析View的draw的流程

    View draw

    SDK中的注释很详细

      public void draw(Canvas canvas) {
            final int privateFlags = mPrivateFlags;
            //判断是否为非法invalidate请求,我们平时调用invalidate即为合法的,即返回false
            final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
                    (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
            //重置标志位为合法invalidate以及需要draw
            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
            int saveCount;
    
            if (!dirtyOpaque) {
                drawBackground(canvas);
            }
    
            // skip step 2 & 5 if possible (common case)
            final int viewFlags = mViewFlags;
           //表示ScrollBar在不使用时,是否渐变消失,默认为true
            boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
            boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
            if (!verticalEdges && !horizontalEdges) {
                // Step 3, draw the content
                if (!dirtyOpaque) onDraw(canvas);
    
                // Step 4, draw the children
                dispatchDraw(canvas);
    
                // 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);
    
                // we're done...
                return;
            }
         .......非正常情况的代码省略
    }
    

    主要看Step.4的dispatchDraw方法,该方法用于绘制child,View中的dispatchDraw方法为空实现,因为View没有child,接下来看看ViewGroup的dispatchDraw方法:

      @Override
     protected void dispatchDraw(Canvas canvas) {
                   ....................
      for (int i = 0; i < childrenCount; i++) {
         //1.先画暂态View,具体解释看下文
         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) {
                    //2.画child,drawChild
                    more |= drawChild(canvas, child, drawingTime);
                }
            }
    ...........
    }
     protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
            return child.draw(canvas, this, drawingTime);
        }
    

    注释1:
    暂态View即通过ViewGroup# addTransientView方法添加的View,该View无法获得焦点,不能响应事件等,它纯粹只用于显示效果,类似补间动画中的view,无法响应事件。
    总结:
    View的draw主要分6个步骤,正常情况下只有4步,省略步骤2、5:
    1.画背景
    2.条件满足则:saveLayer,为渐变消失准备
    3.画自己内容(平时开发当中的onDraw)
    4.画Child(通过调用ViewGroup的dispatchDraw方法)
    5.条件满足则:画scrollbar渐变消失,restoreLayer
    6.画前景

    相关文章

      网友评论

        本文标题:View draw流程分析

        本文链接:https://www.haomeiwen.com/subject/vtziqxtx.html