Android View绘制过程

来源:互联网 发布:手机电脑控制软件 编辑:程序博客网 时间:2024/05/16 10:15

​ View经过测量和布局之后,就剩下绘制了;测量和布局是为了确定View尺寸和位置,而绘制就是就是将我们想显示到界面上的东西画到View上。

​ View的绘制过程在draw(Canvas)方法中完成的;这个方法有690多行;但是它做的工作其实很简单,可以总结以下几点:

1. 绘制背景2. 绘制当前View的内容(调用onDraw)3. 绘制当前View的所有子View4. 绘制装饰部分 (前景色,进度条)

而官方注释给出的步骤是6条:

  1. 绘制背景
  2. 如果必要,保存画布图层,以防止衰减(不知道这样翻译对不对,原话:If necessary, save the canvas’ layers to prepare for fading)
  3. 绘制当前View的内容(调用onDraw)
  4. 绘制当前View的所有子View
  5. 如果必要,绘制衰减的边和保存的图层(即第2步保存的图层)
  6. 绘制装饰部分 (前景色,进度条)

具体看一下代码,这里做了一些删减:

public void draw(Canvas canvas) {   //……省略对 mPrivateFlags  的赋值    /* 绘制的6个步骤     *      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);    }    //如果需要跳过第2步和第5步: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);        // Overlay is part of the content and draws beneath Foreground        if (mOverlay != null && !mOverlay.isEmpty()) {            mOverlay.getOverlayView().dispatchDraw(canvas);        }        // 第6步:Step 6, draw decorations (foreground, scrollbars)        onDrawForeground(canvas);        // we're done...        return;    }    //……省略 第2-6步;这里把所有的步骤都走完了;这种情况会比较少见}

通过源码,我们可以看到绘制只需要4步就可以。

我们调用draw()方法就是将我们需要内容画到UI界面上。draw()方法会依次调用onDraw(Canvas),dispatchDraw(Canvas);在View 中这两个方法都是空的。所以根据我们在测量和布局的经验,我们一般就是要重写这种空的方法。恩,对的,我们如果想自定义控件时,还是不要去重写draw(Canvas)方法,还是乖乖重写onDraw(Canvas)或者dispatchDraw(Canvas)方法。这两个方法的调用的时机呢?

  • 我们需要自定义一个View,而不是一组view,那么我们只需要重写onDraw就OK了。onDraw只是绘制本身的内容。
  • ViewGroup已经重写了dispatchDraw(Canvas)方法,它会依次遍历所有的子view,并且会依次调用子View的draw(Canvas)方法。如果我们自己自定义布局,我们就不需要再去重写这个方法了;包括系统提供的那些Layout都没有重写。除非你有的需求比较变态。

ViewGroup重写的dispatchDraw(Canvas)方法,除了会遍历子View的draw(Canvas)方法,去绘制子View,它还会处理它们的动画。

invalidate

​ 另外这里还涉及一个invalidate(boolean)方法,这里传入的是true,其实还有一个方法叫做invalidate(),是一个没有参数的方法,它就是调用的invalidate(true)。这个方法的字面意思是 使作废,那么是使谁作废呢?它的意思是当View可见时,使整个View都作废,那作废之后屏幕不可能什么都不显示,所以之后它会去掉用 draw(Canvas)方法重新绘制。就相当于重新刷新了一下View。当我们有新的内容需要绘制上去的时候,就可以去调用这个方法。

​ 这个方法只能在UI线程下调用,如果实在子线程调用,可以调用postInvalidate方法。

requestLayout

​ 当View发生变化时,比如尺寸和位置;之前的View已经作废了,那么这个方法就会去安排去重新走一遍布局的流程,如果布局的流程正在走,它会等到布局完成再重新走一遍。跟invalidate方法相比,requestLayout方法会重新从 measure—>onMeasure—>layout—>onLayout 重新走一遍,而不会再走绘制流程。而invalidate则只会从dispatchDraw—>draw—>onDraw走一遍。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 外地考驾照需要暂住证怎么办 考驾照期间暂住证过期怎么办 b2驾照扣了6分怎么办 c1驾照扣了11分怎么办 c1驾驶证分扣9分怎么办 驾驶证c照扣6分怎么办 驾照过期1个月怎么办 上海驾驶证b证扣分怎么办 临时牌驾照丢了怎么办 行驶证年审过期两年怎么办 驾证到期了没换怎么办 在非洲被蚊子咬怎么办 身份证丢了被非法贷款怎么办 未满16岁怎么办身份证 放弃继承权后想反悔怎么办 上海居住证积分中社保断怎么办 换驾驶证但是身份证地址变动怎么办 驾驶证b证扣分了怎么办 c1驾证过期没审怎么办 驾照报名三年过期了怎么办 新车行驶证过期了怎么办 行驶证忘了审怎么办 摩托车驾驶证副本丢了怎么办 人被全险车撞了怎么办 被全险车撞了怎么办 驾驶证和行驶证遗失怎么办 户口迁移身份证没换驾照怎么办 户口迁回时身份证掉了怎么办 户口毕业托管身份证掉了怎么办 身份证和户口都掉了怎么办 毕业生户口迁回原籍没身份证怎么办 落户上海后怎么办医保卡 小车临时牌过期了怎么办 驾驶证地址错了一个字怎么办 驾驶证名下车辆有违章怎么办 a2如果扣12分怎么办 b2一次超速12分怎么办 b2本扣了12分怎么办 驾照扣了27分怎么办 大车一次扣12分怎么办 a2驾照扣10分怎么办