View.measure(0, 0)方法什么情况下能正确计算宽高

1.问题

在最新的需求中,想通过getMeasureWidth( )方法获取一个FrameLayout布局的measureWidth值,但由于未进行Measure步骤,所以getMeasureWidth( )最终会返回0。所以想手动调用View.measure(0, 0)方法,主动触发Measure步骤。再获取measureWidth。但该方案对一些View是无效的。下面分析在什么情况下执行measure(0, 0)可得到正确的measureWidth值。

2.分析

提示:分析前假定你已阅读了《View的Measure过程解析》,并熟悉了View的Measure过程

在View.measure(0, 0)中参数是模式和大小的组合值, 0 表示模式为MeasureSpec.UNSPECIFIED,大小为0。所以执行View.measure(0, 0)方法就是告诉View:你自己来决定你的大小吧
当子View收到这个消息后,View会在onMeasure( )方法决定自己的大小,View.onMeasure( )默认的实现如下:

protected int getSuggestedMinimumWidth() {
    return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
}

即根据View的图片资源和View的mMinWidht属性值来决定。

而很多的View都重写onMeasure()方法,用自己的一套方法来决定自己的大小,每种View重写的onMeasure( )的实现方式都不一样。
我们不可能一一分析每种View的onMeasure()的实现细节,下面的从两个实例的运行结果来推断View的决定方式:

  • ImageView

我把layout_width和layout_height都设定为match_parent
View.measure(0, 0)方法什么情况下能正确计算宽高_第1张图片

调用measure(0, 0)测量后,大小还是ic_launcher.png这个图片的大小
这里写图片描述

我把layout_width和layout_height都设定为500dp
View.measure(0, 0)方法什么情况下能正确计算宽高_第2张图片

大小还是ic_launcher.png这个图片的大小
这里写图片描述
通过上面的运行结果我们得出:ImageView决定自己大小的方式是根据设定的图片资源的分辨率来决定ImageView的大小

  • TextView

在布局中任意设置layout_width和layout_height这两个参数
View.measure(0, 0)方法什么情况下能正确计算宽高_第3张图片

最终TextView测量出来的大小值都是固定的, 从而可知道TextView是根据文本内容需要的空间大小来决定TextView的大小。
这里写图片描述

上面通过对ImageView和TextView进行measure(0, 0)操作,我们得出结论:
只有layout_width和layout_height都设置为wrap_content才得到正确的值,设置为其它的参数不能得到正确的measureHeight和measureWidth。

View.measure(0, 0)方法中的参数是 MeasureSpec.UNSPECIFIED + 0, 表达的意思是:你自己来决定你的大小吧
MeasureSpec.AT_MOST + MeasureSpec.size,表达的意思是:你自己来决定你的大小吧,但是最大值不能超过MeasureSpec.size
MeasureSpec. EXACTLY + MeasureSpec.size,表达的意思是: 你的大小为MeasureSpec.size

所以当系统自行处理布局流程时,父容器给子View传递的参数是:MeasureSpec.UNSPECIFIED + 0 时,使用measure(0, 0)计算出来的值是正确的,因为系统让子View自行计算自己大小和我们让它自行计算自己大小,计算的结果都是一样的。
父容器给子View传递的参数是: MeasureSpec.AT_MOST + MeasureSpec.size时,使用measure(0, 0)计算出来的值可能正确可能不正确, 因为系统让子View自行计算自己大小,但大小不能超过MeasureSpec.size,但使用measure(0, 0)时,只是叫子View自己去计算大小,而没有最大值限定。所以如果子View计算出的大小不大于MeasureSpec.size时,measure(0, 0)能正确计算,当View计算出的大小大于MeasureSpec.size时,measure(0, 0)计算出的大小值是不正确的。

而传递给子View的MeasureSpec参数是根据子View的布局参数layout_width/layout_height和所在父View的SpecMode决定。如下表所示:
View.measure(0, 0)方法什么情况下能正确计算宽高_第4张图片

3.总结

上面已经分析完毕,下面总结一下分析后得出的结果:

1. 当一个View的布局参数layout_width/layout_height设定为wrap_content时,一般来说measure(0, 0)能正确计算出长宽值,只有子View计算的大小,大于父View中的限定值时才会出现不正确的情况
2. 当一个View的布局参数layout_width/layout_height设定为match_parent时, 但父View的SpecMode为UNSPECIFIED时,measure(0, 0)计算正常,

你可能感兴趣的:(Android-开发总结,开发中遇到的坑)