ViewTreeObserver不调用onGlobalLayout [英] ViewTreeObserver doesn't call onGlobalLayout

查看:658
本文介绍了ViewTreeObserver不调用onGlobalLayout的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经有使用ViewTreeObserver的活动了,没有任何问题,但是在这种情况下,我没有得到onGlobalLayout回调.

I already have activities where I'm using the ViewTreeObserver without problems, but in this case I don't get the onGlobalLayout callback.

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

Since I get the width of a view after I perform an http API call, the width seems to be already calculated (due to the time that the API call takes). Anyway, to be sure I add a listener to the ViewTreeObserver. But sometimes I don't get the callback (yes, sometimes).

我可以在添加侦听器之前检查宽度,以避免不得不等待回调,但是我不知道为什么有时我没有得到回调.我已检查viewTreeObserver始终存在.

I can check the width before adding the listener to avoid having to wait for the callback, but I don't know why I'm not getting the callback sometimes. I have checked that the viewTreeObserver is always alive.

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
}


编辑:

以防万一,我做了这个辅助方法:

Just in case it helps, I made this helper method:

/**
 * 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();
                }
            }
        });
    }
}

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

With that method you can do for example:

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

推荐答案

摘自有关ViewTreeObserver.OnGlobalLayoutListener的官方文档:

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

Interface definition for a callback to be invoked when the global layout state or the visibility of views within the view tree changes.

如果您的http回调发生在视图(及其子视图)的最后一次可见性更改之后,则通常在OnGlobalLayoutListener中没有任何回调.

If your http callback comes after the last visibility change of your view (with his subviews) it's normal that you aren't getting any callback in your OnGlobalLayoutListener.

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

The case in which you will get a callback is when your http request is finished before all your views are created, so you will get a callback in your onGlobalLayout that is referred to the finish of the drawing of the views.

这篇关于ViewTreeObserver不调用onGlobalLayout的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆