view的绘制流程

首先简单说下流程

onMeasure
对view进行大小测量,如果是viewgroup的话还得对child进行大小测量
onLayout
如果就是个view的话这里也没啥处理的,如果是viewgroup的话,就是通过cihld.layout()设置child显示的位置

draw
这个就是只要方法了,它里边会有逻辑调用onDraw和dispatchDraw
onDraw

dispatchDraw

draw方法研究

 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
        int saveCount;

        if (!dirtyOpaque) {
            drawBackground(canvas);
        }
// skip step 2 & 5 if possible (common case)
 final int viewFlags = mViewFlags;//它的值在下边的代码里可以看到,构造方法里初始化的
        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);

            drawAutofilledHighlight(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);

            // Step 7, draw the default focus highlight
            drawDefaultFocusHighlight(canvas);

            if (debugDraw()) {
                debugDrawFocus(canvas);
            }

            // we're done...
            return;
        }

ondraw为啥不执行可以看这里http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1014/1765.html
,我是看不下去了,里边都是十六进制来回与或非操作,脑袋都大了。具体细节就不看了,

我们直接看结论即可

    /**
     * If this view doesn't do any drawing on its own, set this flag to
     * allow further optimizations. By default, this flag is not set on
     * View, but could be set on some View subclasses such as ViewGroup.
     *
     * Typically, if you override {@link #onDraw(android.graphics.Canvas)}
     * you should clear this flag.
     *
     * @param willNotDraw whether or not this View draw on its own
     */
    public void setWillNotDraw(boolean willNotDraw) {
        setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK);
    }

viewgroup默认不进行ondraw操作的,构造方法里就执行了setFlags(WILL_NOT_DRAW, DRAW_MASK)

···
public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);

    initViewGroup();
    initFromAttributes(context, attrs, defStyleAttr, defStyleRes);
}

private void initViewGroup() {
    // ViewGroup doesn't draw by default
    if (!debugDraw()) {
        setFlags(WILL_NOT_DRAW, DRAW_MASK);
    }

···

看下viewFlags的初始化

    public View(Context context) {
        mContext = context;
        mResources = context != null ? context.getResources() : null;
        mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO;

public static final int SOUND_EFFECTS_ENABLED = 0x08000000;

public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000;

public static final int FOCUSABLE_AUTO = 0x00000010;

static final int FADING_EDGE_HORIZONTAL = 0x00001000;

static final int FADING_EDGE_VERTICAL = 0x00002000;

设置背景引起的改变

    public void setBackgroundDrawable(Drawable background) {
        computeOpaqueFlags();

        if (background == mBackground) {
            return;
        }

//省略n多代码
computeOpaqueFlags();

//
    protected void computeOpaqueFlags() {
        // Opaque if:
        //   - Has a background
        //   - Background is opaque
        //   - Doesn't have scrollbars or scrollbars overlay

        if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) {
            mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND;
        } else {
            mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND;
        }

        final int flags = mViewFlags;
        if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) ||
                (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY ||
                (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) {
            mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS;
        } else {
            mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS;
        }
    }

线性布局设置divider

我记得线性布局不用设置背景,弄个divider也可以执行onDraw方法的,去看一下为啥
又看到了属性的setWillNotDraw,参数结果肯定是false拉。

    public void setDividerDrawable(Drawable divider) {
        if (divider == mDivider) {
            return;
        }
        mDivider = divider;
        if (divider != null) {
            mDividerWidth = divider.getIntrinsicWidth();
            mDividerHeight = divider.getIntrinsicHeight();
        } else {
            mDividerWidth = 0;
            mDividerHeight = 0;
        }

        setWillNotDraw(!isShowingDividers());
        requestLayout();
    }

结论

与或非这一堆操作就不想看那些flag了。所以只要知道结论就行了,具体细节就不研究了。

我们只需要知道,viewgroup要执行onDraw方法,那么就需要调用setWillNotDraw(false)方法
,当然也可以通过setbackground来实现,设置背景的话也会修改flag。
另外特殊的线性布局,如果设置了divider,divider高度不为0,也是可以进入ondraw方法的。

你可能感兴趣的:(view的绘制流程)