onGlobalLayout differentiate between various invocations
Asked Answered
E

3

12

I have a logo view, which is a full screen fragment containing single ImageView. I have to perform some operations after the logo image is completely visible.

Following code is used to invoke the special task

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        ImageView logoImageMaster = new ImageView(getContext());
        //logoImageMaster.setImageResource(resID); //even after removing this, i am getting the callback twice
        try {
            // get input stream
            InputStream ims = getActivity().getAssets().open("product_logo.png");
            // load image as Drawable
            Drawable d = Drawable.createFromStream(ims, null);
            // set image to ImageView
            logoImageMaster.setImageDrawable(d);
        }
        catch(IOException ex) {

        }
        logoImageMaster.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {  //FIXME get called twice. Check this out, no info to distinguish first from second
//                Log.e("PANEL", "onGlobalLayout of Logo IV ---------------------------------");
                    activityInterface.doSpecialLogic();
            }
        });
        return logoImageMaster;
    }

My exact problem is, onGlobalLayout is called twice for this view hierarchy.

I know that onGlobalLayout is invoked in performTraversal of View.java hence this is expected.

For my use case of Single parent with Single child view, I want to distinguish the view attributes such that doSpecialLogic is called once[onGlobalLayout is called twice] , after the logo image is completely made visible. Please suggest some ideas.

Epochal answered 2/8, 2016 at 11:0 Comment(0)
O
5

OnGlobalLayoutListener gets called every time the view layout or visibility changes. Maybe you reset the views in your doSpecialLogic call??
edit as @Guille89 pointed out, the two set calls cause onGlobalLayout to be called two times

Anyhow, if you want to call OnGlobalLayoutListener just once and don't need it for anything else, how about removing it after doSpecialLogic() call??

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
             //noinspection deprecation
              logoImageMaster.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                    } else {
             logoImageMaster.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    }
activityInterface.doSpecialLogic();
Oleum answered 3/9, 2016 at 8:1 Comment(6)
Hi, I still get twice, now i set only one time, pls see the updates to the questionEpochal
No, I am not reseting the view in doSpecialLogicEpochal
well as per the docs onGlobalLayout = "Callback method to be invoked when the global layout state or the visibility of views within the view tree changes" so the views must be reloading again which calls the onGlobalLayout twice.Oleum
Just realised, you don't want to stop two calls to the onGlobalLayout but rather to have doSpecialLoagic() called once. How about setting a boolean flag before doSpecialLogic?? i.e. something like if(!flag) {doSpecialLogic; flag=true;}Oleum
I understand, my setting up a flag, then i need to book keep on that .Epochal
I know that would be simpler, but if i can still differentiate various onGlobalLayout calls based on any view state, it would be most useful then i dont need the book-keeping of the flagEpochal
T
1

It seems to be called one time for each set done over the imageView

logoImageMaster.setImageResource(resID);

logoImageMaster.setImageDrawable(d);
Transistorize answered 7/9, 2016 at 9:43 Comment(1)
Hi, I still get twice, now i set only one time, pls see the updates to the questionEpochal
H
1

You should Try using kotlin plugin in android

This layout listener is usually used to do something after a view is measured, so you typically would need to wait until width and height are greater than 0. And we probably want to do something with the view that called it,in your case Imageview

So generified the function so that it can be used by any object that extends View and also be able to access to all its specific functions and properties from the function

[kotlin]
    inline fun <T: View> T.afterMeasured(crossinline f: T.() -> Unit) {
    viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
    override fun onGlobalLayout() {
    if (measuredWidth > 0 && measuredHeight > 0) {
    viewTreeObserver.removeOnGlobalLayoutListener(this)
    f()
    }
    }
    })
    }
[/kotlin]

Note: make sure that ImageView is described properly in the layout. That is its layout_width and layout_height must not be wrap_content. Moreover, other views must not result in this ImageView has 0 size.

Hotbed answered 9/9, 2016 at 21:10 Comment(1)
Sorry. I am not allowed to use any of the external pluginsEpochal

© 2022 - 2024 — McMap. All rights reserved.