ViewTreeObserver不会调用onGlobalLayout

时间:2016-02-16 21:48:52

标签: android layout

我已经开展过活动,我可以毫无问题地使用ViewTreeObserver,但在这种情况下我无法获得onGlobalLayout回调。

由于在执行http API调用后获得了视图的宽度,因此宽度似乎已经计算好了(由于API调用所花费的时间)。无论如何,要确保我向ViewTreeObserver添加一个监听器。但有时候我没有得到回调(是的,有时候)。

我可以在添加监听器之前检查宽度,以避免等待回调,但我不知道为什么我有时没有得到回调。我检查过viewTreeObserver总是活着。

ViewTreeObserver viewTreeObserver = view.getViewTreeObserver();

assert viewTreeObserver.isAlive();

viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout()   // Not called sometimes, why?
    {
        view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
        doSomething(view.getWidth());
    }
});

现在我将使用这个技巧:

int width = view.getWidth();

if (width > 0) {
    doSomething(view.getWidth());
} else {
    // use the ViewTreeObserver
}

修改

为了防止它有用,我制作了这个辅助方法:

/**
 * Runs code on global layout event, useful when we need to do something after the layout is done
 * (like getting the view real measure). The runnable is only called once at most.
 *
 * A typical `shouldRun` function can be `v -> v.getWidth() > 0` since it checks that the view has some width,
 * so we can calculate things depending on that.
 *
 * @param shouldRun receives the `view` and decides if the runnable should run (it is checked when this method is called, and also on global layout).
 *
 * See: http://stackoverflow.com/questions/35443681/viewtreeobserver-doesnt-call-ongloballayout
 */
public static void runOnGlobalLayout(final View view, final Func1<View,Boolean> shouldRun, final Runnable runnable)
{
    if (shouldRun.call(view)) {
        runnable.run();
        return;
    }

    final ViewTreeObserver viewTreeObserver = view.getViewTreeObserver();

    if (viewTreeObserver.isAlive()) {
        viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if (shouldRun.call(view)) {
                    view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                    runnable.run();
                }
            }
        });
    }
}

使用该方法,您可以执行以下操作:

runOnGlobalLayout(someLayout, v -> v.getWidth() > 0, () -> {
    int availableWidth = someLayout.getWidth();
    // draw things in layout, etc.
});

1 个答案:

答案 0 :(得分:5)

关于ViewTreeObserver.OnGlobalLayoutListener的官方文档:

  

当视图树中的全局布局状态或视图的可见性发生更改时要调用的回调的接口定义。

如果您的http回调是在视图的最后一次可见性更改(带有子视图)之后发生的,那么您在OnGlobalLayoutListener中没有收到任何回调是正常的。

您将获得回调的情况是您的http请求在创建所有视图之前完成,因此您将在onGlobalLayout中获得一个回调,该回调被称为视图。