这个问题已经多次以各种形式提出,但我还没有找到明确的答案。
我需要能够在容器的初始布局(Views
)之后获得后代contentView
的维度和位置。在这种情况下所需的尺寸是一个不可预测的视图(组) - 可能有多行文本,最小高度以容纳装饰等。我不想在每个布局通道上都做到这一点({{1 }})。我需要的测量来自一个深度嵌套的孩子,所以覆盖每个容器的onLayout
/ onLayout
似乎是一个糟糕的选择。我不打算做任何导致循环的事情(事件中的触发事件)。
Romain Guy曾暗示我们可以在onMeasure
的构造函数中.post
Runnable
(AFAIK将位于UI线程中)。这似乎适用于大多数设备(在我个人的4个中有3个),但在Nexus S上失败。看起来Nexus S没有任何尺寸,直到每个孩子完成一次通过,并且没有正确的尺寸何时调用View
ed post
的{{1}}方法。我尝试计算布局传递(在Runnable
中)并与run
进行比较,后者再次在4个中有3个,但是不同的3个(在Droid Razr上失败,似乎只做了一次传递 - 和得到所有测量 - 无论孩子的数量如何)。我尝试了上述的各种排列(正常发布;发布到onLayout
;将getChildCount
投射到Handler
并调用getContext()
...所有人的结果相同。< / p>
我最终使用了一个可怕的可耻的不好的黑客,通过检查目标群体的高度与其父母的身高 - 如果它不同,则意味着它已被布局。显然,不是最好的方法 - 但是唯一似乎在各种设备和实现之间可靠地工作的方法。我知道我们可以使用没有内置事件或回调,但还有更好的方法吗?
TYIA
/编辑对我来说,最重要的是Nexus S不会等到布局完成后Activity
一个runOnUiThread
,就像是这样的情况一样我测试过的所有其他设备,以及Romain Guy和其他人的建议。我还没有找到一个好的解决方法。有吗?
答案 0 :(得分:9)
我使用OnGlobalLayoutListener成功了。
它在我的Nexus S上运行得很好
final LinearLayout marker = (LinearLayout) findViewById(R.id.distance_marker);
OnGlobalLayoutListener listener = new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//some code using marker.getHeight(), etc.
markersContainer.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
};
marker.getViewTreeObserver().addOnGlobalLayoutListener(listener);
答案 1 :(得分:3)
我自己使用OnGlobalLayoutListener的经验是,在所有子视图都已布局之前,它并不总是等待触发。因此,如果您正在查找特定子项(或子项的子项等)视图的维度,那么如果您在onGlobalLayout()方法中测试它们,您可能会发现它们反映了布局的某些中间状态进程,而不是将向用户显示的最终(静止)状态。
在测试中,我注意到通过执行postDelayed()延迟一秒钟(显然,竞争条件,但这仅用于测试),我确实得到了正确的值(对于子视图的子项) ),但如果我做了一个没有延迟的简单post(),我得到了错误的值。
我的解决方案是避免使用OnGlobalLayoutListener,而是在我的顶级视图中使用dispatchDraw()的直接覆盖(包含我需要测量其子级的子视图)。默认的dispatchDraw()绘制当前视图的所有子视图,因此如果您在调用dispatchDraw()中的super.dispatchDraw(canvas)后调用代码执行测量,那么您可以确定所有子视图在进行测量之前将绘制视图。
以下是这样的:
@Override
protected void dispatchDraw(Canvas canvas) {
//Draw the child views
super.dispatchDraw(canvas);
//All child views should have been drawn now, so we should be able to take measurements
// of the global layout here
post(new Runnable() {
@Override
public void run() {
testAndRespondToChildViewMeasurements();
}
});
}
当然,在您进行这些测量之前会进行绘图,而且要防止这种情况为时已晚。但如果这不是问题,那么这种方法似乎非常可靠地提供了后代视图的最终(静态)测量。
一旦你得到了你需要的测量结果,你需要在testAndRespondToChildViewMeasurements()的顶部设置一个标志,这样它就可以返回而不做任何进一步的操作(或者在dispatchDraw()覆盖自身中进行类似的测试) ,因为,与OnGlobalLayoutListener不同,没有办法删除此覆盖。