这篇文章只是一个简单自定义知识总结,浅谈自定义View。
在学习自定义View之前我们先了解一下几个概念。
一 ViewRoot,DecorView
ViewRoot是什么? ViewRoot对应于ViewRootImpl类,看到了很多人写的是viewtree的根节点,其实它跟View没有任何关系,也不是ViewTree的根节点,ViewTree的根节点往往是DecorView,DecorView的根是PhoneWindow,所以ViewRoot不是ViewTree的根节点,ViewRoot将DecorView attach到PhoneWindow上,连接WindowManager和DecorView的纽带。
二 View的绘制流程概括
View的绘制流程是从ViewRoot的performTraversals方法开始,然后调用onmeasure,onlayout,ondraw最终绘制出来view。(此处不做深入探讨,以后会分析)
performTraversals的工作流程
performTraversals会依次调用
- performMeasure---->measure--->onMeasure---->从父容器传递到子View
- performLayout ---->layout ---->onLayout--->从从父容器传递到子View
- performDraw--->draw---->onDraw--->从父容器传递到子View
三 Mearsure,Layout,Draw的工作流程
Mearsure
测量分为两种情况
- view 的测量
- view的测量是通过measure的方法来测量的
- measure方法调用了onMeasure方法,传入参数MeasureSpec,其中 onMeasure方法对MeasureSpec进行处理
- onMeasure方法中调用了setMeasuredDimension()方法去设置View的具体宽高值
- getDefaultSize()此方法传入MeasureSpec,由此来确定宽高。
- ViewGroup的测量
1.先遍历去调用所有子元素的measure方法,各个子元素再递归去执行这个流程.
- ViewGroup结合自己的特性(比如竖直,水平等)给出自身的measure值。
这里有一个重要的类需要解释那就是MeasureSpec
MeasureSpec
(选自开发艺术探索)
MeasureSpec代表一个32位int值,高2位代表SpecMode,低30位代表SpecSize,SpecMode是指测量模式,而specSize是指在某种测量模式下的规格大小。
其中SpecMode有三个类
- UNSPECIFIED
父容器不对View有任何限制,要多大给多大,这种情况一般用于系统内部,表示一种测量的状态。
- EXACTLY
父容器已经测量出View所需要的精确大小,这个时候View的最终大小就是SpecSize所指定的值。它对应于LayoutParams中的match_parent(填充父元素,因为父元素的大小是固定的所以也相当于是具体数值)和具体的数值这两种模式。
- AT_MOST
父容器指定了一个可用大小即SpecSize,View大小不能大于这个值,(就是有最大限制)具体是什么值要看不同View的具体实现。它对应于LayoutParams中的Wrap_content
Layout
用来确定子元素的位置,当ViewGroup的位置被确定后,它在onLayout中会遍历所有的子元素并调用自身的layout方法,在layout方法中onLayout方法会被调用。layout方法确定View本身的位置,onLayout方法则会确定所有子元素的位置。
这里有一个小问题需要解释一下就是:getMeasuredHeight(getMeasuredWidth),和getHeight(getWidth)的区别
友情链接:Android开发之getMeasuredWidth和getWidth区别从源码分析
getMeasuredWidth方法获得的值是setMeasuredDimension方法设置的值,它的值在measure方法运行后就会确定
getWidth方法获得是layout方法中传递的四个参数中的mRight-mLeft,它的值是在layout方法运行后确定的
一般情况下在onLayout方法中使用getMeasuredWidth方法,而在除onLayout方法之外的地方用getWidth方法。
4.在几乎所有的情况下都是相等的。
draw
这个过程就比较简单了,就是根据上面的数据进行绘制到屏幕上。