ViewTreeObserver does not call onGlobalLayout

I already have actions in which I use ViewTreeObserver without problems, but in this case I do not get the onGlobalLayout .

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

I can check the width before adding a listener to avoid having to wait for a callback, but I don't know why I sometimes don't get a callback. I checked that ViewTreeObserver 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()); } }); 

Now I will use this trick:

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

EDIT

Just in case this 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 this method you can do, for example:

 runOnGlobalLayout(someLayout, v -> v.getWidth() > 0, () -> { int availableWidth = someLayout.getWidth(); // draw things in layout, etc. }); 
+5
source share
1 answer

From the official documentation on ViewTreeObserver.OnGlobalLayoutListener :

Defines the interface for the callback that is called when the global layout state or visibility of the views in the view tree changes.

If your HTTP callback appears after the last change in the visibility of your view (with its subtitles), it is normal that you do not receive a callback in your OnGlobalLayoutListener .

The case when you get a callback is when your HTTP request is completed before all your views are created, so you will get a callback in your onGlobalLayout , which refers to the finish of the drawing.

+4
source

Source: https://habr.com/ru/post/1243179/


All Articles