View的measure阶段

measure的三个部分:预测量、布局窗口、最终测量

预测量

预测量时ViewRootImpl给mView的specSize:

1.第一次预测量时,给应用可用的最大尺寸。

2.窗口为悬浮窗的时候,给应用可用的最大尺寸。

3.其他情况,在mView的LayouParams.width/height为MATCH_PARENT或WRAP_CONTENT时,使用窗口最新尺寸,为精确值时,使用这个精确值作为specSize。(窗口最新尺寸是取自ViewRootImpl.mWinFrame:Rect,而不是ViewRootImpl.mWidth/mHeight,也不是mParams.width/height。mWinFrame保存了窗口的尺寸和位置并与WMS同步,mWidth/mHeight保存了窗口布局后的窗口尺寸,除非WMS单方面改变了窗口尺寸,否则mWidth/mHeight和mWinFrame的尺寸相同)

预测量使用measureHierarchy(),其中包含了协商算法,正在进行一次控件树测量的时performMeasure(),协商就是多次使用不同的参数调用performMeasure()。 协商只在窗口为悬浮窗(width或height指定为WRAP_CONTENT)时才执行。

4.需要进行协商的原因:想让悬浮窗布局尽可能更美观,从而再第一次预测量时限定悬浮窗的宽度。预测量阶段最多会测量三次。第一次给的specSize为小于给应用可用的最大尺寸(假设为y)的一个值,假设是x。如果测量结果不满意,则放宽宽度,第二次测量的specSize设为(x+y)/2;如果还是不满意,则再放宽,第三次测量的specSize为y。

布局窗口与最终测量

预测量是算出mView(ViewRootImpl的根View)的期望尺寸,即窗口的期望尺寸。在下一步调用IWindowSession.relayoutWindow()时,就使用此尺寸为参数,告诉WMS希望分配一块这么大的Surface,relayoutWindow()会输出返回Surface及其尺寸与位置。如果分配的Surface与期望的尺寸不一致,则需以Surface的实际尺寸作为mView的specSize重新测量,这样控件树就在给定mView的尺寸的基础上测量出每个View尺寸。因为就最终测量时没有协商余地,测量一次就完了,所以直接调用performMeasure()。

当预测量得到mView的尺寸与窗口最新尺寸不一致时才需要重新布局,只有布局窗口后,WMS分配返回的Surface的实际尺寸与布局窗口传入的期望尺寸不一致时才需要最终测量。

跟窗口相关的属性会绑定到控件树每个View的mAttachInfo中

View#getMeasuredWidth/HeightAndState():获得View的测量值和是否满意的标志的复合型int

View#getMeasuredWidth/Height():获得View的测量值,布局控件树阶段就是使用该值作为宽高

自定义View实现measure阶段:

复写protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法,如果时View,则直接根据MeasureSpec和控件实际情况确定宽高,并调用setMeasuredDimension(int measuredWidth, int measuredHeight)。如果时ViewGroup,则再onMeasure中先逐个调用child.measure(int widthMeasureSpec, int heightMeasureSpec),并根据上个child的测量结果去计算下一个child的MeasureSpec。在所有child都测量完成后,根据所有child的结果去确定ViewGroup自身的最终尺寸。

MeasureSpec

由高二位的specMode和低30位的specSize组成。specMode根据自身的width/height和父控件的specMode决定。specMode

有EXACTLY、ATMOST、UNSPECIFIED.

可以通过ViewGroup的public static int getChildMeasureSpec(int spec, int padding, int childDimension)获得child的MeasureSpec。RootView(如decorView)的MeasureSpec由ViewRootImpl的private static int getRootMeasureSpec(int windowSize, int rootDimension)获得。

measuredWidth

由最高二位的state和低30位的size组成。state就是too_small或者非too_small.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值