How to remove ViewTreeObserver in Xamarin?

半城伤御伤魂 提交于 2019-12-11 08:03:03

问题


Let's just say I need to get and set a View's height. In Android, it's known you can get a view height only after it's drawn. If you're using Java, many answers, one of the most well-known way is like this one below, taken from this answer:

view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            view.getHeight(); //height is ready
        }
    });

Thus I search C#/Xamarin version, and found this works:

int viewHeight = 0;
ViewTreeObserver vto = view.ViewTreeObserver;
vto.GlobalLayout += (sender, args) =>
{
    viewHeight = view.Height;
};

Thing is, it fired again and again. In Java version, it can be removed with view.getViewTreeObserver().removeOnGlobalLayoutListener(this);

How to do it in C#\Xamarin? Should I resort to using boolean properties to know whether it's executed or not? Is there not way to do it like the android one?


回答1:


If you are using C# Events, avoid using anonymous events if you need to unsubscribe, or you can implement the IOnGlobalLayoutListener and add/remove the listener:

C# EventHandler Style:

Create an EventHandler method for the event to invoke:

void Globallayout_handler(object sender, EventArgs e)
{
    // ViewTreeObserver.IOnGlobalLayoutListener events
}

Subscribe:

var viewTreeObserver = aView.ViewTreeObserver;
viewTreeObserver.GlobalLayout += Globallayout_handler;

Unsubscribe:

var viewTreeObserver = aView.ViewTreeObserver;
viewTreeObserver.GlobalLayout -= Globallayout_handler;

Java Listener Style in C#:

Add and implement ViewTreeObserver.IOnGlobalLayoutListener:

public class CustomButtonRenderer : Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer,
ViewTreeObserver.IOnGlobalLayoutListener
{
   ~~~~

    public void OnGlobalLayout()
    {
       // ViewTreeObserver.IOnGlobalLayoutListener events
    }
}

Now you can use the Java way to add and remove this listener:

aView.ViewTreeObserver.RemoveOnGlobalLayoutListener(this); 

aView.ViewTreeObserver.AddOnGlobalLayoutListener(this); 



回答2:


Even though the answer given by ShshiHangover is correct in principle, the unsubscribing didn't work for me as expected (using the regular method #1).

The reason is probably that the ViewTreeObserver in the called method can be different from the one the event handler subscribed to, so removing it may not work (i.e., the handler method is called continuously).

The correct way of doing this is to unsubscribe from the event sender object while ensuring that IsAlive yields true:

void ViewTreeObserver_GlobalLayout(object sender, EventArgs e)
{
    ViewTreeObserver vto = (ViewTreeObserver)sender;
    if (vto.IsAlive) {
         vto.GlobalLayout -= ViewTreeObserver_GlobalLayout;
    }
}



回答3:


Neither @Daniel or @SushiHangover methods would actually unsubscribe for me (maybe an sdk bug?). My only solution was to set a bool flag on first run. It would be nice to know how to actually unsubscribe however...

Getting the ViewTreeObserver via sender never seems to be IsAlive whereas getting the tree from the View does. However either way the event doesn't get properly removed.

    private void Setup()
    {
        cameraView = FindViewById<SurfaceView>(Resource.Id.camera_view);

        //need to wait for view to inflate to get size
        isSetup = false;
        ViewTreeObserver vto = cameraView.ViewTreeObserver;
        vto.GlobalLayout += Vto_GlobalLayout;
    }

    void Vto_GlobalLayout(object sender, System.EventArgs e)
    {
        //this didn't work either
        //ViewTreeObserver vto = cameraView.ViewTreeObserver;
        //vto.GlobalLayout -= Vto_GlobalLayout;

        ViewTreeObserver vto = (ViewTreeObserver)sender;
        if (vto.IsAlive)
            vto.GlobalLayout -= Vto_GlobalLayout; //even after removing it seems to continue to fire...
        if (!isSetup)
        {
            isSetup = true;
            DoYourCodeNow();
        }
    }


来源:https://stackoverflow.com/questions/42575932/how-to-remove-viewtreeobserver-in-xamarin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!