浅分析android绘画机制

上篇文章探讨了android事件分发机制,这一篇简单的介绍一下,android的绘画机制。

首先,先写一个类继承于LinearLayout,并且重新相应的方法。
这里写图片描述
然后在使用这个布局,看看日志的输出。
这里写图片描述
所以,android的绘画顺序是 onMeasure –> onLayout –> onDraw
顾名思义,对应的是“测量”,“布局”,“绘制”。

下面,咱们来按顺序一个一个来看。

onMeasure()

一直跟踪onMeasure,可以发现,ViewGroup并没有这个函数,在View中才可以看到。View中onMeasure是中measure中被调用。我们看看measure的介绍。

/**
     * <p>
     * This is called to find out how big a view should be. The parent
     * supplies constraint information in the width and height parameters.
     * </p>

这个介绍的意思就是说,这个measure的是根据父亲的约束信息去测量view的大小。在看下去,我们可以发现,measure只是一个测量的架构而已,具体的测量在onMeasure中。看看onMeasure的代码。

这里写图片描述

这里没有干什么时,只是把默认尺寸set进去而已。这里很好理解,不同的View的测量方式应该是不一样的,所以onMeasure方法应该被子类重写。常用的线性布局,相对布局,ListView都重写了这个方法。

好,measure往下就写到这里,更多进阶的介绍以后有机会再来谈。

现在,往上面走。measure在哪里被调用的呢?我们在View中搜measure,发现搜不到被调用的地方。接着看看measure的权限,发现是public的,也就是说,这个方法是在其他地方调用的。

好,关于绘制方面,就得去ViewRootImpl里面找一找。
果然,找到了。

这里写图片描述
ViewRootImol在performMeasure方法中调用了View的measure方法。
好,在往上走,performMeasure方法又是在哪里被调用的!

private void performTraversals() {
    .....
    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    ....

    if (lp.verticalWeight > 0.0f) {
     ...
     measureAgain = true;
     }
    if (measureAgain) {
     performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    }
    ....
    if (didLayout) {
      performLayout(lp, desiredWindowWidth, desiredWindowHeight);
    ...
     if (!cancelDraw && !newSurface) {
      ...
      performDraw();
      ...
    }
}

performTraversals方法特别的长,我就把有最最最主要的代码提取的出来了。看到这里我们就明白了,performTraversals方法其实就是整一个测量,布局,绘制的框架啊。

这里首先调用了performMeasure()去测量,然后下面如果measureAgain为true,就再调用了一次performMeasure(),我们在最上面的日志输出,可以看到onMeasure输出了两次,有可能就是这里的原因!(这里由于功力不够,只能先猜测)

然后接着进行布局,绘制。好,布局和绘制等会再谈,接着往上走。performTraversals方法在哪里被调用呢?

我们发现doTraversal方法调用了performTraversals方法。然后在往上追寻。看到这一段代码。

final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
        doTraversal();
    }
}

就不在贴代码了。继续往上可看到scheduleTraversals()是发送 Callback,其中有mTraversalRunnable这个对象。继续往上,看看scheduleTraversals()在哪里被调用。发现,在很多地方都调用了这个方法,比如:requestLayout(请求布局),requestFitSystemWindows(请求系统窗口)等等。而这里,涉及到Activty的启动,就先跟踪到这里。

通过这一系列的跟踪,可以知道,ViewRootImpl是在控制测量,布局,绘制的主要类。这个类可以理解成是窗体和View之间的桥梁。它不是一个View。

好,接着看布局和绘制。

onLayout( ) 和onDraw( )

看到ViewGroup的中onLayout()是个抽象方法。在View的onLayout()是个空方法。所以,布局的实现是给子View去自己做。其实也必须这样。面向对象的三大特性之一泛化,就是要把未来不知道的东西交给未来。这里布局只能交给未来还未出生的孩子。

viewGroup中没有onDraw方法,因为viewGroup是容器,容纳了很多View,而绘制是相对view而言的。所以viewGroup没有重写onDraw方法。但是,viewGroup去调用了View的draw方法,而从上面的介绍我们可以知道,draw中调用了onDraw。好,那么去看看View的onDraw方法呗。进去一看,空方法…….

绘制是在测量和布局之后,测量被很多子View给重新设置了规则,布局更是完完全全交给子View,所以绘制一样也是交给子View的。

而在线性布局,相对布局等等布局中,就可以看到测量,布局,绘制的具体实现了。

往上走呢?布局和绘制往上的和布局是一样的。其实在上面的performTraversals( )方法就可以看到,分别调用了performMeasure()、performLayout()、performDraw()。所有流程是一样的。

有个问题没有提到:在测量,布局,绘制中,ViewGroup和子View是如何协调的呢?

可能具体实现会不一样,但是整一个框架是和我的上一篇文章“事件分发机制”类似的(http://blog.csdn.net/s2311307/article/details/74780023),可以先去看看那一篇文章,然后试着自己分析一下。

感谢你看到这里,下下个星期分析android里的Handle机制。

最后,上面这些分析是我边看牛人的文章边看源码写出来的,当然其中有不足,也有错误,后面随着我发现出来我会更改的。

当然,你也可以指出这些错误或者补充这些不足,我会虚心的接受,改正。如果你有不懂的地方,可以留言,我看到会耐心解答。

贴一篇非常好的分析绘制流程的文章:http://blog.csdn.net/feiduclear_up/article/details/46772477,里面的分析简单易懂。作为一名开发者,懂一些源码还是必要的!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值