Forum Xamarin.iOS

Need to disable swipe gesture of FlyLayout behavior in Xamarin Forms Shell in iPad

JoannaGJoannaG Member ✭✭

Im trying to disable swipe gesture of FlyLayout in iOS. Tried with below code but not working in iPad and works fine in iPhone.

[assembly: ExportRenderer(typeof(AppShell), typeof(iOSShellRenderer))]
namespace TestMenuSwipe.iOS
{

                public class iOSShellRenderer : ShellRenderer
                {
                                IShellFlyoutRenderer flyoutRenderer;

                                protected override IShellFlyoutRenderer CreateFlyoutRenderer()
                                {
                                                flyoutRenderer = base.CreateFlyoutRenderer(); 
                                                return flyoutRenderer;
                                }

                                public override void ViewWillAppear(bool animated)
                                {
                                                base.ViewWillAppear(animated);
                                                var type = flyoutRenderer.GetType();
                                                var property = type.GetProperty("PanGestureRecognizer", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                                                var value = property.GetValue(flyoutRenderer);

                                                UIPanGestureRecognizer recognizer = value as UIPanGestureRecognizer;
                                                recognizer.Enabled = false;


                                }
                }
}

Is there any other property instead "PanGestureRecognizer" in iPad? Any suggesstions?

Best Answer

  • JoannaGJoannaG ✭✭
    edited March 24 Accepted Answer

    In ShellRenderer.cs

    [assembly: ExportRenderer(typeof(Shell), typeof(ShellExtendedRenderer))]
    namespace Alden.One.Client.iOS.Renderers
    {
    public class ShellExtendedRenderer : ShellRenderer
    {
    IShellFlyoutRenderer flyoutRenderer;

        protected override IShellFlyoutRenderer CreateFlyoutRenderer()
        {
            if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad)
            {
                return new CustomTabletFlylayoutRenderer();
            }
            flyoutRenderer = base.CreateFlyoutRenderer();
    
            return flyoutRenderer;
        }
    }
    

    }

    In CustomTabletFlyLayoutRederer.cs

    public class CustomTabletFlylayoutRenderer : UISplitViewController, IShellFlyoutRenderer, IFlyoutBehaviorObserver
    {
    #region IShellFlyoutRenderer

        UIViewController IShellFlyoutRenderer.ViewController => this;
    
        UIView IShellFlyoutRenderer.View => View;
    
        void IShellFlyoutRenderer.AttachFlyout(IShellContext context, UIViewController content)
        {
            _context = context;
            _content = content;
    
            FlyoutContent = _context.CreateShellFlyoutContentRenderer();
            FlyoutContent.WillAppear += OnFlyoutContentWillAppear;
            FlyoutContent.WillDisappear += OnFlyoutContentWillDisappear;
    
            ((IShellController)_context.Shell).AddFlyoutBehaviorObserver(this);
    
            ViewControllers = new UIViewController[]
            {
                FlyoutContent.ViewController,
                content
            };
        }
    
        #endregion
    
        #region IFlyoutBehaviorObserver
    
        void IFlyoutBehaviorObserver.OnFlyoutBehaviorChanged(FlyoutBehavior behavior)
        {
            switch (behavior)
            {
                case FlyoutBehavior.Disabled:
                    PreferredDisplayMode = UISplitViewControllerDisplayMode.PrimaryHidden;
                    PresentsWithGesture = false;
                    break;
                case FlyoutBehavior.Flyout:
                    PreferredDisplayMode = UISplitViewControllerDisplayMode.PrimaryHidden;
              **  // Disabled Swipe gesture to display FlyLayout on panning in default view 
                    PresentsWithGesture = false;** 
                    _isPresented = false;
                    _context.Shell.SetValueFromRenderer(Shell.FlyoutIsPresentedProperty, false);
                    break;
                case FlyoutBehavior.Locked:
                    PreferredDisplayMode = UISplitViewControllerDisplayMode.AllVisible;
                    break;
            }
    
            _flyoutBehavior = behavior;
        }
    
        #endregion
    
        IShellContext _context;
        UIViewController _content;
        bool _isPresented;
        FlyoutBehavior _flyoutBehavior;
        bool _disposed;
    
        IShellFlyoutContentRenderer FlyoutContent { get; set; }
    
        void OnFlyoutContentWillAppear(object sender, EventArgs e)
        {
            _isPresented = true;
            _context.Shell.SetValueFromRenderer(Shell.FlyoutIsPresentedProperty, true);
        }
    
        void OnFlyoutContentWillDisappear(object sender, EventArgs e)
        {
            _isPresented = false;
            _context.Shell.SetValueFromRenderer(Shell.FlyoutIsPresentedProperty, false);
        }
    
        void OnShellPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == Shell.FlyoutIsPresentedProperty.PropertyName)
            {
                OnFlyoutIsPresentedChanged();
            }
        }
    
        protected virtual void ToggleFlyout()
        {
            var barButtonItem = DisplayModeButtonItem;
            UIApplication.SharedApplication.SendAction(barButtonItem.Action, barButtonItem.Target, null, null);
        }
    
        protected virtual void OnFlyoutIsPresentedChanged()
        {
            var presented = _context.Shell.FlyoutIsPresented;
    
            if (_isPresented != presented)
                ToggleFlyout();
        }
    
        public override void ViewDidLoad()
        {
            base.ViewDidLoad();
    
            _context.Shell.PropertyChanged += OnShellPropertyChanged;
        }
    
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
    
            if (disposing)
            {
                if (!_disposed)
                {
                    _disposed = true;
                    FlyoutContent.WillAppear -= OnFlyoutContentWillAppear;
                    FlyoutContent.WillDisappear -= OnFlyoutContentWillDisappear;
                    ((IShellController)_context.Shell).RemoveFlyoutBehaviorObserver(this);
                }
    
                FlyoutContent = null;
                _content = null;
                _context = null;
            }
        }
    }
    

    Works fine.Disabled Swipe Gesture in iPad .

Answers

  • ColeXColeX Member, Xamarin Team Xamurai
    edited March 23

    Use type.GetProperties to get all the private properties , check the following code

    var s = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance);
    foreach (var i in s)
    {
          Console.WriteLine(i.Name);
    }
    

    Test on iPhone

    Test on IPad

    As you see , there is no similar property like PanGestureRecognizer on ipad , will keep researching . ..

  • JoannaGJoannaG Member ✭✭

    @ColeX ,

    If not then can we disable its gesture alone by any other property instead panGestureRecognizer?

    Is there any separate renderer for iPad or any other properties handling gesture?

  • ColeXColeX Member, Xamarin Team Xamurai

    We have to get UISplitViewController in Renderer first ,and set PresentsWithGesture to false ,refer https://stackoverflow.com/a/26187100/8187800 .

    When i tried the following code, unfortunately the swipe gesture still exists .

         //TabletShellFlyoutRenderer is subclass of UISplitViewController
     TabletShellFlyoutRenderer vc = ViewController as TabletShellFlyoutRenderer; 
         vc.PresentsWithGesture = false;
    
  • JoannaGJoannaG Member ✭✭

    @ColeX ,

    I used TabletShellFlyoutRenderer as it is in my project and added PresentsWithGesture = false; in default mode.
    It works.

  • ColeXColeX Member, Xamarin Team Xamurai

    Please post your detailed solution and mark it as answer . @JoannaG

  • JoannaGJoannaG Member ✭✭
    edited March 24 Accepted Answer

    In ShellRenderer.cs

    [assembly: ExportRenderer(typeof(Shell), typeof(ShellExtendedRenderer))]
    namespace Alden.One.Client.iOS.Renderers
    {
    public class ShellExtendedRenderer : ShellRenderer
    {
    IShellFlyoutRenderer flyoutRenderer;

        protected override IShellFlyoutRenderer CreateFlyoutRenderer()
        {
            if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad)
            {
                return new CustomTabletFlylayoutRenderer();
            }
            flyoutRenderer = base.CreateFlyoutRenderer();
    
            return flyoutRenderer;
        }
    }
    

    }

    In CustomTabletFlyLayoutRederer.cs

    public class CustomTabletFlylayoutRenderer : UISplitViewController, IShellFlyoutRenderer, IFlyoutBehaviorObserver
    {
    #region IShellFlyoutRenderer

        UIViewController IShellFlyoutRenderer.ViewController => this;
    
        UIView IShellFlyoutRenderer.View => View;
    
        void IShellFlyoutRenderer.AttachFlyout(IShellContext context, UIViewController content)
        {
            _context = context;
            _content = content;
    
            FlyoutContent = _context.CreateShellFlyoutContentRenderer();
            FlyoutContent.WillAppear += OnFlyoutContentWillAppear;
            FlyoutContent.WillDisappear += OnFlyoutContentWillDisappear;
    
            ((IShellController)_context.Shell).AddFlyoutBehaviorObserver(this);
    
            ViewControllers = new UIViewController[]
            {
                FlyoutContent.ViewController,
                content
            };
        }
    
        #endregion
    
        #region IFlyoutBehaviorObserver
    
        void IFlyoutBehaviorObserver.OnFlyoutBehaviorChanged(FlyoutBehavior behavior)
        {
            switch (behavior)
            {
                case FlyoutBehavior.Disabled:
                    PreferredDisplayMode = UISplitViewControllerDisplayMode.PrimaryHidden;
                    PresentsWithGesture = false;
                    break;
                case FlyoutBehavior.Flyout:
                    PreferredDisplayMode = UISplitViewControllerDisplayMode.PrimaryHidden;
              **  // Disabled Swipe gesture to display FlyLayout on panning in default view 
                    PresentsWithGesture = false;** 
                    _isPresented = false;
                    _context.Shell.SetValueFromRenderer(Shell.FlyoutIsPresentedProperty, false);
                    break;
                case FlyoutBehavior.Locked:
                    PreferredDisplayMode = UISplitViewControllerDisplayMode.AllVisible;
                    break;
            }
    
            _flyoutBehavior = behavior;
        }
    
        #endregion
    
        IShellContext _context;
        UIViewController _content;
        bool _isPresented;
        FlyoutBehavior _flyoutBehavior;
        bool _disposed;
    
        IShellFlyoutContentRenderer FlyoutContent { get; set; }
    
        void OnFlyoutContentWillAppear(object sender, EventArgs e)
        {
            _isPresented = true;
            _context.Shell.SetValueFromRenderer(Shell.FlyoutIsPresentedProperty, true);
        }
    
        void OnFlyoutContentWillDisappear(object sender, EventArgs e)
        {
            _isPresented = false;
            _context.Shell.SetValueFromRenderer(Shell.FlyoutIsPresentedProperty, false);
        }
    
        void OnShellPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == Shell.FlyoutIsPresentedProperty.PropertyName)
            {
                OnFlyoutIsPresentedChanged();
            }
        }
    
        protected virtual void ToggleFlyout()
        {
            var barButtonItem = DisplayModeButtonItem;
            UIApplication.SharedApplication.SendAction(barButtonItem.Action, barButtonItem.Target, null, null);
        }
    
        protected virtual void OnFlyoutIsPresentedChanged()
        {
            var presented = _context.Shell.FlyoutIsPresented;
    
            if (_isPresented != presented)
                ToggleFlyout();
        }
    
        public override void ViewDidLoad()
        {
            base.ViewDidLoad();
    
            _context.Shell.PropertyChanged += OnShellPropertyChanged;
        }
    
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
    
            if (disposing)
            {
                if (!_disposed)
                {
                    _disposed = true;
                    FlyoutContent.WillAppear -= OnFlyoutContentWillAppear;
                    FlyoutContent.WillDisappear -= OnFlyoutContentWillDisappear;
                    ((IShellController)_context.Shell).RemoveFlyoutBehaviorObserver(this);
                }
    
                FlyoutContent = null;
                _content = null;
                _context = null;
            }
        }
    }
    

    Works fine.Disabled Swipe Gesture in iPad .

  • JoannaGJoannaG Member ✭✭

    @ColeX ,

    I cant mark it as answer. You can confirm from our side and accept my answer.

  • ShaneNeuvilleShaneNeuville USUniversity ✭✭

    This will be fixed by the following PR
    https://github.com/xamarin/Xamarin.Forms/pull/10632

Sign In or Register to comment.