onMeasure() 以 EXACTLY 和规格大小 0 调用

2024-01-21

调试自定义视图覆盖时onMeasure()方法 我看到有几个对此方法的调用。
我只处理视图的高度,宽度规格始终保持不变。
有时我接到一个关于(高度)MeasureSpec 的电话getMode() == EXACTLY and getSize() == 0.
This 没有意义 and 与Android文档相矛盾:

MeasureSpecs are used to push requirements down the tree from parent to child.
A MeasureSpec can be in one of three modes:

UNSPECIFIED: This is used by a parent to determine the desired dimension of a child
view. For example, a LinearLayout may call measure() on its child with the height set
to UNSPECIFIED and a width of EXACTLY 240 to find out how tall the child view wants
to be given a width of 240 pixels.

EXACTLY: This is used by the parent to impose an exact size on the child. The child
must use this size, and guarantee that all of its descendants will fit within this 
size.

AT_MOST: This is used by the parent to impose a maximum size on the child. The child
must guarantee that it and all of its descendants will fit within this size.

如果我按照假设做(孩子必须使用这个尺寸), setMeasureDimension(specWidth, sepcHeight)我收到一个异常,告诉我视图的宽度和高度必须 > 0。
我怀疑这个调​​用是因为在布局 XML 中,视图有layout_weight="1"并且,根据文档建议 http://developer.android.com/guide/topics/ui/layout/linear.html#Weight:

创建一个线性布局,其中每个子项使用相同数量的 屏幕上的空间,将每个视图的 android:layout_height 设置为 “0dp”

但是,当 MeasureSpec 模式为 EXACTLY 时,大小应该 > 0。或者至少在这些情况下,在文档中应该遵循一些规则。

这是代码:

    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int specHeight = MeasureSpec.getSize(heightMeasureSpec);
    int specWidth = MeasureSpec.getSize(widthMeasureSpec);

    int desiredHeight = Math.max(BOX_MIN_HEIGHT, HSVColorPickerPreference.this.boxHeight);

    int chosenHeight = 0;

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    if( heightMode == MeasureSpec.UNSPECIFIED ) {
        chosenHeight = desiredHeight;
    } else if( heightMode == MeasureSpec.AT_MOST ) {
        chosenHeight = Math.min(specHeight, desiredHeight);
    } else if( heightMode == MeasureSpec.EXACTLY ) {
        chosenHeight = specHeight;
    }

    setMeasuredDimension(specWidth, chosenHeight);

这是日志,注意最后一次调用onMeasure():

03-29 08:17:13.388: D/ValueSlider(1384): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:-2147483435)
03-29 08:17:13.388: W/ValueSlider(1384): MeasureSpec AT_MOST, specSize=213, desiredSize=40, chosenSize=40
03-29 08:17:13.388: D/AlphaSlider(1384): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:-2147483435)
03-29 08:17:13.388: W/AlphaSlider(1384): MeasureSpec AT_MOST, specSize=213, desiredSize=40, chosenSize=40
03-29 08:17:13.388: D/ValueSlider(1384): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073741824)
03-29 08:17:13.388: W/ValueSlider(1384): MeasureSpec EXACTLY, specSize=0, desiredSize=40, chosenSize=0
03-29 08:17:13.388: D/AlphaSlider(1384): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073741824)
03-29 08:17:13.388: W/AlphaSlider(1384): MeasureSpec EXACTLY, specSize=0, desiredSize=40, chosenSize=0
03-29 08:17:13.508: D/ValueSlider(1384): + onSizeChanged(w:579, h:0, oldw:0, oldh:0)
03-29 08:17:13.508: D/AndroidRuntime(1384): Shutting down VM
03-29 08:17:13.508: W/dalvikvm(1384): threadid=1: thread exiting with uncaught exception (group=0xb2fe0180)
03-29 08:17:13.518: E/AndroidRuntime(1384): FATAL EXCEPTION: main
03-29 08:17:13.518: E/AndroidRuntime(1384): java.lang.IllegalArgumentException: width and height must be > 0
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.graphics.Bitmap.createBitmap(Bitmap.java:603)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.graphics.Bitmap.createBitmap(Bitmap.java:585)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at com.UturpatShuPepper.lib.HSVColorPickerPreference$Slider.onSizeChanged(HSVColorPickerPreference.java:962)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.View.setFrame(View.java:11361)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.View.layout(View.java:11272)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.View.layout(View.java:11278)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.ViewGroup.layout(ViewGroup.java:4224)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.widget.LinearLayout.onLayout(LinearLayout.java:1399)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.View.layout(View.java:11278)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.ViewGroup.layout(ViewGroup.java:4224)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.widget.RelativeLayout.onLayout(RelativeLayout.java:925)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.View.layout(View.java:11278)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.ViewGroup.layout(ViewGroup.java:4224)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.View.layout(View.java:11278)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.ViewGroup.layout(ViewGroup.java:4224)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.View.layout(View.java:11278)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.ViewGroup.layout(ViewGroup.java:4224)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.widget.LinearLayout.onLayout(LinearLayout.java:1399)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.View.layout(View.java:11278)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.ViewGroup.layout(ViewGroup.java:4224)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.View.layout(View.java:11278)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.ViewGroup.layout(ViewGroup.java:4224)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.View.layout(View.java:11278)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.ViewGroup.layout(ViewGroup.java:4224)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.View.layout(View.java:11278)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.ViewGroup.layout(ViewGroup.java:4224)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1489)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2442)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.os.Handler.dispatchMessage(Handler.java:99)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.os.Looper.loop(Looper.java:137)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at android.app.ActivityThread.main(ActivityThread.java:4424)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at java.lang.reflect.Method.invokeNative(Native Method)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at java.lang.reflect.Method.invoke(Method.java:511)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
03-29 08:17:13.518: E/AndroidRuntime(1384):     at dalvik.system.NativeStart.main(Native Method)

由于我终于明白发生了什么事,我将答案留在这里以供将来参考:

Android 正在做它在测量 UI 组件时必须做的事情。
如果用户(在本例中是我)不遵循简单的规则,则可能会发生 EXACTLY 0。
如果你只检查 0 尺寸,它就可以变得无害。onSizeChanged()方法。但如果您像我一样避免混合测量模式,那就更好了。解释如下。

我在 XML 加权视图中定义(使用layout_weight)。这些是问题中提到的自定义视图。我的错误是还尝试要求视图的特定高度

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

罪魁祸首是线条

int desiredHeight = Math.max(BOX_MIN_HEIGHT, HSVColorPickerPreference.this.boxHeight);

. . . 

    chosenHeight = Math.min(specHeight, desiredHeight);

. . .

这与加权布局的启发式直接冲突。为什么?让我们以 3 个权重=1 的小部件为例,其中一个表现不佳,如上所述。

当 LineraLayout 第一次传递其子级时,它会让它们变得狂野并请求它们想要的任何大小。在我们的示例中,2 个小部件将要求尽可能多的信息,自定义小部件将要求适度的信息,小于最大值。

第二遍是杀手锏,LinearLayout 不知道请求的加权小部件之一比它应该的要少,总而言之,它有一个为其定义的权重。 LinearLayout 查看第一遍请求的总测量值,发现它超出了它必须给出的值。然后,它计算增量溢出,并进行另一遍在加权小部件之间分配溢出。 因此,自定义视图小部件必须削减超过其请求的大小,使其大小保持为 0。

这种情况类似于和朋友去喝啤酒。你点了一瓶啤酒,你的朋友点了啤酒、薯条、沙拉等等。晚上结束时,支票会平分给每个人,你最终支付的费用比你喝的啤酒还要多。我的自定义视图也是如此。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

onMeasure() 以 EXACTLY 和规格大小 0 调用 的相关文章

随机推荐