android视图学习---从源码角度来理解onMeasure过程
前面的几篇文章写的都非常好的,非常的了不起,介绍的非常的详细
view的绘制:onMeasure onLayout onDraw 执行流程 【这里其实就是RootViewImpl 里面setView之后的一个流程】
这里是ViewRoot的子类,也叫实现类里面的ViewRootImpl
android怎么把view添加到窗口的:这里面进一步让我们知道整个视图的组成是有window,phoneWindow,decorview【这里面从setContentView,到addView 其实就走到setView】
这里是ViewRoot里面的
surface分析:这里面更深一步的让我们知道了activity是怎么获得一块显存,然后把视图画出来的,ViewRoot在这一步如何跟系统服务交互的,也就是怎么拿到显存的,
ViewRoot是整个显示系统中最为关键的东西,看起来这个东西好像和View有那么点关系,其实它根本和View等UI关系不大,它不过是一个Handler罢了,唯一有关系的就是它其中有一个变量为Surface类型
正是ViewRoot是一个handle类的派生,就让activityTread和System Service 进程服务搞起来了,
接下来的内容又回到view的绘制过程里面,再一次看看onMeasure详细的绘制流程,
从源码步骤来看:
1.setView()函数里面:
有行代码 requestLayout(),只是执行的第一部,
2.在requestLayout()里面:
执行了调度遍历 scheduleTraversals();
3.在调度遍历函数scheduleTraversals里面:
发送了一个空的handle消息
4.在handleMessage里面:
调用 执行遍历函数 performTraversals();到了这一步,也就是基本到了文章1里面说的绘制流程了,但是我们只是分析下onMeasure的详细过程
5.在performTraversals函数里面:这个函数太长了,
如果是初次调用:host.dispatchAttachToWindow() 这个函数的作用就是把视图与window窗口关联起来,
这里面详细有三个函数:onAttachToWindow();参数信息
listener.onViewAttachToWindow();回调
onWindowVisibilityChanged()
host.fitSystemWindow():这一步计算视图跟window之间的padding
而且这里面要非常的注意,执行了requestLayout()方法,一层一层的调用父视图
最后一步就是拿到window的宽和高
如果不是初次调用:直接拿到window的宽和高 供后面的Measure 测量用的
6.在measure里面:
有两个参数,宽和高,这个是父亲传递给孩子的规格,而这个规格的测量是调用getRootMeasure(window的期望孩子的宽高,LayoutParams的宽高)
7.onMeasure()函数:
这个韩式在measure里面调用的,只有你要求我重新绘制,或者高度和宽度变了,我才重新绘制 调用SetMeasureDimension()
8.SetMeasureDimension():这个函数非常的重要,但是里面的代码非常的简单,也是我们重载需要写的,它决定了测量之后获得的宽高
9.getDefaultSize :返回一个默认值,这个默认值调用了 makMesaureSpec 这个函数也非常的简单,size+mode,是二进制的加法
整个过程就结束了,这就是整个onMeasure的详细过程,当然这里面还涉及到非常的详细知识。
下面的文章是参考:
一、Measure本质
小福:我今天分享是的measure架构设计相关的,先问一个问题,measure的本质是什么?
小黑:这个我知道,是Android系统创建UI界面的measure、layout、draw三步骤的第一步,主要用于测量视图大小,更详细点说是把“相对值”(WRAP_CONTENT, FILL_PARENT, MATCH_PARENT)转换为具体指的过程。
小福:小黑说的对,再问一个问题,视图大小指的是什么?
小白:视图大小是在视图在屏幕上显示的大小,也就是开发的时候通过layout_width与layout_heigh设置的?
小福:小白说的只是其中一个作为开发人员的角度。Android系统设计中Canvas是无穷大的,假如一个屏幕的大小是320 * 480 ,但是layout_width="480px", layout_heigh="800px",很明显视图的宽高大于实际屏幕大小。 问题来了,视图的大小到底是屏幕上显示的大小,还是视图的实际大小(即使是超过了屏幕大小)?
小黑:具体视图显示大小是由开发人员设置,之后由我控件开发工程师在onMeasure中决定,如果向小福说的尺寸,即使超过屏幕我可以决定是width=320, heigh = 480 还是widt= 480, heigh = 800 ,决定权在我这里,一会在我分享的时候会写一个Demo来演示。 (视图根据绘制大小不同分类:内容型视图、图形型视图)
小白:Canvas是什么?小福:这个在之后分享draw过程的时候在详细讨论,可以笼统的理解为画画时使用的画布。
小福:Measure的本质是把视图布局时使用的相对值转换为具体值的过程。
二、Measure代码流程
小福:先从源码看下measure执行流程,看看这些过程中都做了些什么。以下都是android.view.ViewRootImpl.java类中的源码
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
public final class ViewRootImpl extends Handler implements ViewParent, View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
// 1 所有子视图的requestLayout方法,最总都会触发根视图此方法 public void requestLayout() { checkThread(); // 需要重新布局 mLayoutRequested = true;
scheduleTraversals(); }
// 调度遍历 public void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true;
.....
// 当前类继承自Handler,发出一个空消息,目的是加入Message队列 sendEmptyMessage(DO_TRAVERSAL); } }
@Override public void handleMessage(Message msg) { switch (msg.what) {
...
case DO_TRAVERSAL: ... // 处理DO_TRAVERSAL消息 performTraversals(); ... break;
..... } }
// 执行遍历 private void performTraversals() {
final View host = mView;
int desiredWindowWidth; int desiredWindowHeight; int childWidthMeasureSpec; int childHeightMeasureSpec; ......
if (mLayoutRequested && !mStopped) { ...... childWidthMeasureSpec = getRoot 您可能想查找下面的文章:文章分类最近更新的内容
|