自定义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的值.