最新消息:文章中包含代码时,请遵守代码高亮规范!

Android View的绘制流程【原创】

Android 王 伟 210浏览 0评论

自定义View的时候,我们就需要了解Android中View的绘制流程,这样才能更好的进行代码的编写。大家都知道自定义View时,需要重写onMeasure(),onDraw()方法,如果是ViewGroup除了要重写onMeasure(),onDraw()方法还要重写onLayout()方法。绘制流程大家也只知道measure,layout,draw三个步骤但具体有什么联系却不太清楚。我们来看View的源码,首先是measure方法。

public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
   ......
    if (forceLayout || needsLayout) {
        ......
        if (cacheIndex<0 || sIgnoreMeasureCache) {
            // measure ourselves, this should set the measured dimension flag back
            onMeasure(widthMeasureSpec, heightMeasureSpec);
            mPrivateFlags3 = ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
        } else {
            long value = mMeasureCache.valueAt(cacheIndex);
            // Casting a long to int drops the high 32 bits, no mask needed
            setMeasuredDimensionRaw((int) (value<<32), (int) value);
            mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
        }
        ......
    }

    mOldWidthMeasureSpec = widthMeasureSpec;
    mOldHeightMeasureSpec = heightMeasureSpec;

    mMeasureCache.put(key, ((long) mMeasuredWidth)<<32 |
            (long) mMeasuredHeight&0xffffffffL); // suppress sign extension
}

在这里,我们看到了在这里调用了onMeasure()方法,我们去看看onMeasure()方法是怎么写的。

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
            getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}

这里我们看到了很熟悉的setMeasuredDimension()方法,这个方法是自定义View时在最后必须写的方法。他是设置宽高的。

这个时候宽高已经测量好了。接下来是Layout()方法。

public void layout(int l, int t, int r, int b) {
    ......
    if (changed || (mPrivateFlags&PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
      onLayout(changed, l, t, r, b);
       ......
    }

    mPrivateFlags|=~PFLAG_FORCE_LAYOUT; 
mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;
 } 

在这里我们看到了调用的onLayout方法。View的onLayout方法是个空方法。

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
}

说明onLayout是需要我们完全自定义的。最后是draw部分,draw也是最重要的。

public void draw(Canvas canvas) {
 ...... 
if (!dirtyOpaque) { 
drawBackground(canvas);//绘制背景 
} 
.......
if (!dirtyOpaque) onDraw(canvas);
dispatchDraw(canvas);
onDrawForeground(canvas);
}

绿色部分显示分别是View的绘制。首先是drawBackground()方法,它是绘制背景的。那么如果你自定义View时,需要在绘制背景之前绘制某些东西,那么就重写draw()方法,然后在super.draw(),方法里进行代码的编写就可以了。接着是onDraw方法,也是我们大家最熟悉的方法,是绘制主题内容的。但是也可以分为两种情况,一种是在super.onDraw()方法之前,一种是在super.onDraw()方法之后。区别大家也都理解,在super.onDraw()之前,表示在绘制背景之后,绘制父类View主体之前进行操作,而在之后呢就是在父类View主体内容绘制完成之后进行绘制。接着是dispatchDraw()方法,这是主要针对ViewGroup的,是绘制子View。也分为之前之后的情况。都是类似的。最后是onDrawForeground()方法,是绘制滑动相关和前景的。最常见的ListView,GridView以及ScollerView的ScollerBar就是在这里进行绘制的。

为了大家的记忆,我从网上盗了一副图来更加方便的记忆:

总体上来说,一个View是先measure–>onMeasure–>Layout–>onLayout–>draw–>drawBackground–>onDraw–>dispatchDraw–>onDrawForeground。整个过程就是这样的。

转载时请注明出处及相应链接,本文永久地址:http://blog.it985.com/22346.html


pay_weixin
pay_weixin
微信打赏
pay_weixin
支付宝打赏
感谢您对作者Bob的打赏,我们会更加努力!    如果您想成为作者,请点我

您必须 登录 才能发表评论!