首先简单说下流程
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方法的。