getMeasuredWidth返回完全错误的值

28

我需要为了给其他的视图留出空间而测量一个View。我使用以下代码来实现:

ViewGroup view = ...;
view.setPadding(10, 0, 10, 0);
int wrapContent = RelativeLayout.LayoutParams.WRAP_CONTENT;
int specWidth = MeasureSpec.makeMeasureSpec(wrapContent, MeasureSpec.AT_MOST);
view.measure(specWidth, specWidth);
int questionWidth = view.getMeasuredWidth();

在 Android 4.3 模拟器上预期的结果正常。

然而,在 Samsung Galaxy XCover 2 (S7710) Android 4.1.2 手机上返回的测量宽度是16777214... 我尝试了所有方法,使用View.MEASURED_SIZE_MASK掩码,但没有帮助。

您能提供一些帮助吗?先感谢您!


1
知道您的viewgroup内部有什么(提供xml)会有所帮助。我刚遇到了同样的问题并解决了它,我认为您的情况也不会有太大差异,但让我们看看您的布局。//您无需掩盖getMeasured*()返回的内容,这些值已经被掩盖了。 - Ivan Bartsov
1
没有XML。ViewGroup的子项是动态实例化并添加的。 - WonderCsabo
请检查下面的答案 - Ivan Bartsov
1个回答

66

makeMeasureSpec()方法传递WRAP_CONTENT而不是实际值是没有用的,我认为这些参数不应该一起使用。

使用实际的约束值作为第一个参数(如父视图的大小或屏幕的尺寸),并配合 MeasureSpec.AT_MOST 模式,这基本上是 Math.min() -- 其中参数是您放入规范中的值和视图的期望维度。

MeasureSpec.EXACTLY 将使用规范值,MeasureSpec.UNSPECIFIED 将使用视图的期望值。因此,如果您没有任何约束(例如,如果将视图放入 ScrollView 中),您的选项是 MeasureSpec.UNSPECIFIED -- 和任何值作为第一个参数。

所以,{大师们,如果我说错了,请纠正我},您可以在除了MeasureSpec.EXACTLY之外的任何模式下获得WRAP_CONTENT的行为。

话虽如此,请尝试:

ViewGroup view = ...;
view.setPadding(10, 0, 10, 0);
// Either this
int specWidth = MeasureSpec.makeMeasureSpec(parentWidth, MeasureSpec.AT_MOST);
// Or this
int specWidth = MeasureSpec.makeMeasureSpec(0 /* any */, MeasureSpec.UNSPECIFIED);
view.measure(specWidth, specWidth);
int questionWidth = view.getMeasuredWidth();

PS 关于 16777214,有趣的一件事情是看一下它的二进制表示:https://www.google.ru/search?q=16777214+in+binary 它是-2(即 LayoutParams.WRAP_CONTENT 的常量值),但是通过逻辑操作截去了8个最高有效位(因此没有负号),在 measure() 的调用堆栈中,有一些东西会执行这个操作 :) 我想知道这是否是一个 bug。也许它应该检查参数是否为负数并抛出异常之类的。


4
23小时后,您将会得到一份奖励,因为您的回答不仅值得点赞。非常感谢您提供了精彩的解释,我已经花了将近4个小时来琢磨这个问题。 - d3m0li5h3r
@d3m0li5h3r 谢谢,很高兴我的答案对你有所帮助) - Ivan Bartsov
非常好的解释。真的很喜欢人们这样开发答案的方式。让我很容易理解并根据我的需求进行调整。非常感谢! - Olaia
1
先生,通过这篇文章,您已经获得了进入瓦尔哈拉的资格。 - Garcon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接