1.繼承ViewGroup為什么不會調(diào)用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 調(diào)用onDraw方法
if (!dirtyOpaque) onDraw(canvas);
// Step 4, draw the children
dispatchDraw(canvas);
// Step 6, draw decorations (foreground, scrollbars)
onDrawForeground(canvas);
}
我們自定義View 繼承 ViewGroup,復(fù)寫onDraw()方法.onDraw()沒有被調(diào)用.
從上面的 draw(Canvas canvas) 的方法的
if (!dirtyOpaque) onDraw(canvas);
只要dirtyOpaque為false才會調(diào)用onDraw方法.而dirtyOpaque 由下面這行代碼控制.
final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
(mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
其實(shí)dirtyOpaque 就是由privateFlags決定的,而privateFlags是由mPrivateFlags決定的.
下面找mPrivateFlags怎么賦值的.
在View的構(gòu)造方法中的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的構(gòu)造方法找的initViewGroup()方法
private void initViewGroup() {
// ViewGroup doesn't draw by default
if (!debugDraw()) {
//這個調(diào)用了View的方法.
setFlags(WILL_NOT_DRAW, DRAW_MASK);
}
......
}
setFlags方法導(dǎo)致mPrivateFlags 重新賦值 為 true.所以 if (!dirtyOpaque) onDraw(canvas); 這樣的onDraw() 方法就進(jìn)不來了.導(dǎo)致ViewGroup不會調(diào)用onDraw() 方法.
源碼分析完畢.
2.為什么給設(shè)置背景又可以調(diào)用onDraw方法?
那我們看一下設(shè)置背景的方法
public void setBackground(Drawable background) {
setBackgroundDrawable(background);
}
調(diào)用了setBackgroundDrawable方法
/**
* @deprecated use {@link #setBackground(Drawable)} instead
*/
@Deprecated
public void setBackgroundDrawable(Drawable background) {
computeOpaqueFlags();
....省略一大段代碼
computeOpaqueFlags();
....省略一點(diǎn)點(diǎn)代碼
invalidate(true);
invalidateOutline();
}
我們可以發(fā)現(xiàn)在setBackgroundDrawable調(diào)用了computeOpaqueFlags方法重新計算mPrivateFlags的值.接著調(diào)用invalidate方法觸發(fā)onDraw方法.
3.怎么解決繼承ViewGroup不能會繪制的問題?
目的:改成mPrivateFlags就可以解決了.
3.1 重寫 dispatchDraw(canvas) 方法,在里面做繪制.因?yàn)?dispatchDraw方法沒有做判斷.一定會調(diào)用.
public void draw(Canvas canvas) {
// Step 3, draw the content 調(diào)用onDraw方法
if (!dirtyOpaque) onDraw(canvas);
// Step 4, draw the children
dispatchDraw(canvas);
// Step 6, draw decorations (foreground, scrollbars)
onDrawForeground(canvas);
}
3.2 設(shè)置背景
//默認(rèn)給一個透明背景
setBackgroundColor(Color.TRANSPARENT);
當(dāng)然前提要判斷有沒有背景.
3.3 調(diào)用setFlags改成 mPrivateFlags值.
public void setWillNotDraw(boolean willNotDraw) {
setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK);
}
還有其他方法.主要的思路就是去改成mPrivateFlags的值.