自定义View

自定义View - 4.ViewGroup不会调用onDraw(

2018-06-10  本文已影响1人  zsj1225

1.继承ViewGroup为什么不会调用onDraw方法?

1.1 ViewGroup的源码,ViewGroup里面没有onDraw(Canvas canvas)方法.
1.2 找到ViewGroup的父类View.
1.3 主要的画方法是draw(Canvas canvas) 方法

public void draw(Canvas canvas) {
    // Step 3, draw the content 调用onDraw方法
     if (!dirtyOpaque) onDraw(canvas);

    // Step 4, draw the children
     dispatchDraw(canvas);

    // Step 6, draw decorations (foreground, scrollbars)
     onDrawForeground(canvas);
}

我们自定义View 继承 ViewGroup,复写onDraw()方法.onDraw()没有被调用.
从上面的 draw(Canvas canvas) 的方法的

if (!dirtyOpaque) onDraw(canvas);

只要dirtyOpaque为false才会调用onDraw方法.而dirtyOpaque 由下面这行代码控制.

final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
                (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);

其实dirtyOpaque 就是由privateFlags决定的,而privateFlags是由mPrivateFlags决定的.
下面找mPrivateFlags怎么赋值的.
在View的构造方法中的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;
        }
    }

在ViewGroup的构造方法找的initViewGroup()方法

    private void initViewGroup() {
        // ViewGroup doesn't draw by default
        if (!debugDraw()) {
            //这个调用了View的方法.
            setFlags(WILL_NOT_DRAW, DRAW_MASK);
        }
       ......
    }

setFlags方法导致mPrivateFlags 重新赋值 为 true.所以 if (!dirtyOpaque) onDraw(canvas); 这样的onDraw() 方法就进不来了.导致ViewGroup不会调用onDraw() 方法.

源码分析完毕.

2.为什么给设置背景又可以调用onDraw方法?

那我们看一下设置背景的方法

    public void setBackground(Drawable background) {
        setBackgroundDrawable(background);
    }

调用了setBackgroundDrawable方法

/**
     * @deprecated use {@link #setBackground(Drawable)} instead
     */
    @Deprecated
    public void setBackgroundDrawable(Drawable background) {
        computeOpaqueFlags();
        ....省略一大段代码
        computeOpaqueFlags();
        ....省略一点点代码
        invalidate(true);
        invalidateOutline();
    }

我们可以发现在setBackgroundDrawable调用了computeOpaqueFlags方法重新计算mPrivateFlags的值.接着调用invalidate方法触发onDraw方法.

3.怎么解决继承ViewGroup不能会绘制的问题?

目的:改成mPrivateFlags就可以解决了.

3.1 重写 dispatchDraw(canvas) 方法,在里面做绘制.因为 dispatchDraw方法没有做判断.一定会调用.

public void draw(Canvas canvas) {
    // Step 3, draw the content 调用onDraw方法
     if (!dirtyOpaque) onDraw(canvas);

    // Step 4, draw the children
     dispatchDraw(canvas);

    // Step 6, draw decorations (foreground, scrollbars)
     onDrawForeground(canvas);
}

3.2 设置背景

//默认给一个透明背景
setBackgroundColor(Color.TRANSPARENT);

当然前提要判断有没有背景.

3.3 调用setFlags改成 mPrivateFlags值.

    public void setWillNotDraw(boolean willNotDraw) {
        setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK);
    }

还有其他方法.主要的思路就是去改成mPrivateFlags的值.

上一篇 下一篇

猜你喜欢

热点阅读