Skip to content

Instantly share code, notes, and snippets.

@JimmyPun610
Last active May 4, 2023 09:20
Show Gist options
  • Save JimmyPun610/6d04f3ac59c0f1b1f5520d50f6d9714f to your computer and use it in GitHub Desktop.
Save JimmyPun610/6d04f3ac59c0f1b1f5520d50f6d9714f to your computer and use it in GitHub Desktop.
Xamarin Form swipe to close page behaviour

To Implement swipe down to close behavior, we should attach the behavior to a view.

In XAML

<ContentView x:Name="ViewToMove">
   <ContentView.Behaviors>
     <behavior:SwipeDownToClosePopupPage  CloseAction="ClosePage" ParentView="{x:Reference ViewToMove}"/>  
   </ContentView.Behaviors>
</ContentView>

In C#

using System;
using Xamarin.Forms;

namespace MyApp.Behaviors
{
    public class SwipeDownToClosePopupPage : Behavior<View>
    {
         private PanGestureRecognizer PanGestureRecognizer { get; set; }
        private double TotalY { get; set; }
        private bool isSwipingDownOnComplete { get; set; }

        private double beforeY { get; set; }
        private double updatedY { get; set; }

        /// <summary>
        /// Close action, depends on your navigation mode
        /// </summary>
        public event Action CloseAction;
       
        public static BindableProperty CloseCommandProperty = BindableProperty.Create(nameof(CloseCommand)
            , typeof(ICommand
            ), typeof(SwipeDownToClosePopupPage)
            , null
            , defaultBindingMode: BindingMode.TwoWay
            , propertyChanged: (bindable, value, newValue) => ((SwipeDownToClosePopupPage)bindable).CloseCommand = (ICommand)newValue);
        public ICommand CloseCommand
        {
            get => (ICommand)GetValue(CloseCommandProperty);
            set => SetValue(CloseCommandProperty, value);
        }


        public static BindableProperty ParentViewProperty = BindableProperty.Create(nameof(ParentView)
            , typeof(Element
            ), typeof(SwipeDownToClosePopupPage)
            , null
            , defaultBindingMode: BindingMode.TwoWay
            , propertyChanged: (bindable, value, newValue) => ((SwipeDownToClosePopupPage)bindable).ParentView = (Element)newValue);
        public Element ParentView
        {
            get => (Element)GetValue(ParentViewProperty);
            set => SetValue(ParentViewProperty, value);
        }

        public SwipeDownToClosePopupPage()
        {
            this.PanGestureRecognizer = new PanGestureRecognizer();
        }

        protected override void OnAttachedTo(View v)
        {
            base.OnAttachedTo(v);
            PanGestureRecognizer.PanUpdated += Pan_PanUpdated;
            v.GestureRecognizers.Add(this.PanGestureRecognizer);
        }

        protected override void OnDetachingFrom(View v)
        {
            base.OnDetachingFrom(v);
            PanGestureRecognizer.PanUpdated -= Pan_PanUpdated;
            v.GestureRecognizers.Remove(this.PanGestureRecognizer);
        }

        private void Pan_PanUpdated(object sender, PanUpdatedEventArgs e)
        {
            View v = sender as View;
            switch (e.StatusType)
            {
                case GestureStatus.Started:
                    updatedY = beforeY = e.TotalY;
                    break;

                case GestureStatus.Running:
                    TotalY = e.TotalY;
                    updatedY = TotalY;
                    if (Device.RuntimePlatform == Device.Android)
                        isSwipingDownOnComplete = TotalY > 0;
                    else if(Device.RuntimePlatform == Device.iOS)
                        isSwipingDownOnComplete = updatedY > beforeY;
                    beforeY = updatedY;
                    if (TotalY > 0)
                    {
                        if(ParentView is View view)
                        {
                            if (Device.RuntimePlatform == Device.Android)
                            {
                                view.TranslateTo(0, TotalY + view.TranslationY, 20, Easing.Linear);
                            }

                            else
                            {
                                view.TranslateTo(0, TotalY, 20, Easing.Linear);
                            }
                        }
                    }
                    else
                    {
                        if (ParentView is View view)
                        {
                            double moved = 0.0;
                            if (Device.RuntimePlatform == Device.Android)
                            {
                                moved = view.TranslationY + TotalY < 0 ? 0 : view.TranslationY + TotalY;
                            }
                            else
                            {
                                moved = TotalY < 0 ? 0 : TotalY;
                            }
                            view.TranslateTo(0, moved, 20, Easing.Linear);
                        }
                    }
                    break;
                case GestureStatus.Completed:
                    {
                        if (isSwipingDownOnComplete)
                        {
                            CloseAction?.Invoke();
                            CloseCommand?.Execute(null);
                        }
                        // Reset TranslateY
                        if (ParentView is View view)
                        {
                            view.TranslateTo(0, 0, 20, Easing.Linear);
                        }
                    }
                    break;

                case GestureStatus.Canceled:
                    {
                        // Reset TranslateY
                        if (ParentView is View view)
                        {
                            view.TranslateTo(0, 0, 20, Easing.Linear);
                        }
                    }
                    break;
            }
      
        }
    }
}
@JimmyPun610
Copy link
Author

Hi, I want to use your solution but giving an error like that => EventHandler "SwipeDownToClosePopupPage_CloseAction" with correct signature not found in type "TApp.Extras.SwipeClose"

Whats wrong, you think? Thanks

Hi @Erdogan34 ,

I know it is a bit late, it should be mismatch of parameters of the method.

The event should be no parameter like below

private void ClosePage(){
    // Method for you action
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment