Android视图绘制流程完全解析,带你一步步深入了解View(二) ---站在巨人的肩膀上学习总结

Android视图绘制流程完全解析,带你一步步深入了解View(二) —站在巨人的肩膀上学习总结

详情请看,郭林大神博客 http://blog.csdn.net/guolin_blog/article/details/16330267

总结:
    1,measure方法中onMeasure()
        (这里才是测量并设置View大小的地方,默认会调用getDefaultSize()方法来获取视图的大小)
    2,layout方法中onLayout()
        (onLayout是一个空实现,因为onLayout()过程是为了确定视图在布局中所在的位置,
        而这个操作应该是由布局来完成的,即父视图决定子视图的显示位置)
    3,draw()方法中onDraw()
        onDraw()是一个空方法因为每个视图的内容部分肯定都是各不相同的,
        这部分的功能交给子类来去实现也是理所当然的。

一:onMeasure()

 1,View系统的绘制是从Viewroot的preformTraversals()方法开始执行的
其实它的内部也是调用了View的measure()方法,该方法的两个参数widthMeasureSpec和heightMeasureSpec这两个值分别确定试图的宽高的规格和大小

MeasureSpec 的值由specSize(大小)和specMode(规格)共同组成
    规格有三种:
    1. EXACTLY   ===  MATCH_PARENT 填充
    表示父视图希望子视图的大小应该是由specSize的值来决定的,
    系统默认会按照这个规则来设置子视图的大小,
    开发人员当然也可以按照自己的意愿设置成任意的大小。
    2. AT_MOST   ===  WRAP_CONTENT  包裹
    表示子视图最多只能是specSize中指定的大小,开发人员应该尽可能小得去设置这个视图,
    并且保证不会超过specSize。系统默认会按照这个规则来设置子视图的大小,
    开发人员当然也可以按照自己的意愿设置成任意的大小。
    3. UNSPECIFIED
    表示开发人员可以将视图按照自己的意愿设置成任意的大小,没有任何限制。
    这种情况比较少见,不太会用到。

####2,onMeasure()方法这里才是真正去测量并设置View大小的地方,
   默认会调用getDefaultSize()方法来获取视图的大小

总结一:

1,子试图绘制规矩
    子试图的绘制由父视图、布局文件、以及视图本身共同完成的,父视图会提供给子视图参考的大小,
    而开发人员可以在XML文件中指定视图的大小,然后视图本身会对最终的大小进行拍板。
    在setMeasuredDimension()方法调用之后,我们才能使用getMeasuredWidth()和getMeasuredHeight()
    来获取视图测量出的宽高,以此之前调用这两个方法得到的值都会是0

2,onMeasure(widthMeasureSpec,heightMeasureSpec)的两个参数是父布局
    经过计算后传递给子试图的.

3,但是最外层的根视图,它的widthMeasureSpec和heightMeasureSpec又是从哪里得到的呢?
    getRootMeasureSpec()获取得到widthMeasureSpec和heightMeasureSpec(源码中就给赋值了)

4,如何自定义一个MeasureSpec()?实现对子试图的从新测量?
    //这样就重新定义了规则
    MeasureSpec.makeMeasureSpec()方法重新组装一个MeasureSpec(specSize,specMode)(重要)
    //请求重新绘制
    requestLayout()

5,一个布局的绘制可能有多次的measure,因为子View可能很多
    ViewGroup中定义了一个measureChildren()方法来去测量子视图的大小
    这里首先会去遍历当前布局下的所有子视图,然后逐个调用measureChild()方法来测量相应子视图的大小

二. onLayout()

  1,measure之后,试图大小就已经测量出来了,接下来就是确定试图位置了ViewRoot的performTraversals方法
    会在measure之后用layout方法

    host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);  
    layout()方法接收四个参数,分别代表着左、上、右、下的坐标,
    当然这个坐标是相对于当前视图的父视图而言的
   2,在layout()方法中调用setFrame方法判断试图大小是否改变,是否需要从新measure

####3,onLayout()方法就是一个空方法因为onLayout()过程是为了确定视图在布局中所在的位置,
   而这个操作应该是由布局来完成的,即父视图决定子视图的显示位置

总结二:

    1,在onLayout()过程结束后,我们就可以调用getWidth()方法和getHeight()方法来获取视图的宽高了

重要2,getMeasureWidth()方法在measure()过程结束后就可以获取到了
    而getWidth()方法要在layout()过程结束后才能获取到
    getMeasureWidth()方法中的值是通过setMeasuredDimension()方法来进行设置的,
    而getWidth()方法中的值则是通过视图右边的坐标减去左边的坐标计算出来的。

三. onDraw()

measure和layout的过程都结束后,接下来就进入到draw的过程了,在这里才真正地开始对视图进行绘制
    ViewRoot中的代码会继续执行并创建出一个Canvas对象,然后调用View的draw()方法来执行具体的绘制工作
    draw()方法内部的绘制过程总共可以分为六步

1,对视图背景的绘制
    代码设置,setBackgroundColor()、setBackgroundResource()等方法进行赋值。

2,不重要省略

3,对视图的内容进行绘制,这里是调用onDraw()方法,这个方法是空的,每个试图内容不同,所以该功能
    交给子类实现

4,这一步的作用是对当前视图的所有子视图进行绘制。但如果当前的视图没有子视图,那么也就不需要进行绘制了
5,不重要省略

6这一步的作用是对视图的滚动条进行绘制(view都有的,只是隐藏了)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值