33
votes

I want to preface this by saying I'm completely new to mobile development, Xamarin, C#, .Net.

I'm working on creating a mobile app using Xamarain Forms and have run into the problem of not having the swipe gesture available to me, at least according to the documentation I've seen.

I found this site: http://arteksoftware.com/gesture-recognizers-with-xamarin-forms/

This describes how to add some additional gestures for IOS/Android to be accessible in the context of the form. Before I try to follow this, I wanted to see if anyone else has implemented swipe in a Xamarin Forms app and how they went about it.

My goals are that there has to be a horizontal stack layout. This layout contains 7 buttons, each button reflects a day in the current week. Swiping left on the stack layout will change the button's text to the previous week. Swiping right will change the button's text to the next week.

So I'm also trying to use MVVM for this and XAML. So is it possible for me to separate the swipe left and the swipe right action? I want to use ICommand to pass a certain parameter to a function based on the direction of the swipe.

Any examples of this or any advice would be greatly appreciated.

6
have a look at XLabs tabbed page they have implemented swipe left and right on a tabbed pageUser1
Ok I can give that a look, unfortunately its not implemented in XAML but I might be able to work from that.Kyle
I implemented drag/drop/swipe/pinch gestures for a project with XF but I found it very clunky to do. Especially with the closed and hard-coded nature of XF - they have TapGestureRecognizer hard-coded in a way that you can't just implement another gesture recognizer, add it to the collection and hope it works; also too many private/internal things. The way I went about it was to create a custom ContentView which supports any gestures and custom renderers for it that pass the events to the view's childSten Petrov
Ok thank you. Do you happen to have any examples that were helpful to you that you can point me in the direction of off the top of your head? Related to my 7 buttons described above to reflect a week. I was binding an array of DateTime objects to the buttons and binding the text of each button to an index in that array. However, the problem with this approach is in order for me to trigger a change, the array itself needs to change. I am trying with observablecollection, but is it possible to bind to index of a collection in xaml? I can't find anything online that says either way.Kyle

6 Answers

28
votes

No need third party libraries.. No need to pay.. Just add these two classes & Implement your swipe listeners

Step 1: Copy paste these two classes

SwipeListener.cs

using System;
using Xamarin.Forms;

namespace SwipeLib
{
public class SwipeListener : PanGestureRecognizer
{
    private ISwipeCallBack mISwipeCallback;
    private double translatedX = 0, translatedY = 0;

    public SwipeListener(View view, ISwipeCallBack iSwipeCallBack)
    {
        mISwipeCallback = iSwipeCallBack;
        var panGesture = new PanGestureRecognizer();
        panGesture.PanUpdated += OnPanUpdated;
        view.GestureRecognizers.Add(panGesture);
    }

    void OnPanUpdated(object sender, PanUpdatedEventArgs e)
    {

        View Content = (View)sender;

        switch (e.StatusType) {

            case GestureStatus.Running:

                try {
                    translatedX = e.TotalX;
                    translatedY = e.TotalY;
                } catch (Exception err) {
                    System.Diagnostics.Debug.WriteLine("" + err.Message);
                }
                break;

            case GestureStatus.Completed:

                System.Diagnostics.Debug.WriteLine("translatedX : " + translatedX);
                System.Diagnostics.Debug.WriteLine("translatedY : " + translatedY);

                if (translatedX < 0 && Math.Abs(translatedX) > Math.Abs(translatedY)) {
                    mISwipeCallback.onLeftSwipe(Content);
                } else if (translatedX > 0 && translatedX > Math.Abs(translatedY)) {
                    mISwipeCallback.onRightSwipe(Content);
                } else if (translatedY < 0 && Math.Abs(translatedY) > Math.Abs(translatedX)) {
                    mISwipeCallback.onTopSwipe(Content);
                } else if (translatedY > 0 && translatedY > Math.Abs(translatedX)) {
                    mISwipeCallback.onBottomSwipe(Content);
                } else {
                    mISwipeCallback.onNothingSwiped(Content);
                }

                break;

        }
    }

}
}

ISwipeCallBack.cs

using System;
using Xamarin.Forms;
namespace SwipeLib
{  
public interface ISwipeCallBack
{

    void onLeftSwipe(View view);
    void onRightSwipe(View view);
    void onTopSwipe(View view);
    void onBottomSwipe(View view);
    void onNothingSwiped(View view);
}
}

Step 2: From your Xamarin forms pass the view & also interface obj. Then you get result

In my case I pass the label

 SwipeListener swipeListener = new SwipeListener(lbl_swipe, this);

Step 3: Implement the ISwipeCallBack interface

public partial class SwipeLibPage : ContentPage, ISwipeCallBack

Sample project --> https://github.com/rranjithkumar100/Xamarin-Swipe-Library

15
votes

Xamarin.Forms has introduced SwipeGestureRecognizer :

<BoxView Color="Teal" ...>
    <BoxView.GestureRecognizers>
        <SwipeGestureRecognizer Direction="Left" Swiped="OnSwiped"/>
    </BoxView.GestureRecognizers>
</BoxView>
7
votes

You can always have a look at this simple demo. And use it as follows:

GestureFrame gi = new GestureFrame
        {
            HorizontalOptions = LayoutOptions.FillAndExpand,
            VerticalOptions = LayoutOptions.FillAndExpand,
            BackgroundColor = Color.FromHex("bf3122"),
        };

        gi.SwipeDown += (s, e) =>
        {
            DisplayAlert("Gesture Info", "Swipe Down Detected", "OK");
            ViewModel.SampleCommand.Execute("Swipe Down Detected");
        };

        gi.SwipeTop += (s, e) =>
        {
            DisplayAlert("Gesture Info", "Swipe Top Detected", "OK");
            ViewModel.SampleCommand.Execute("Swipe Top Detected");
        };

        gi.SwipeLeft += (s, e) =>
        {
            DisplayAlert("Gesture Info", "Swipe Left Detected", "OK");
            ViewModel.SampleCommand.Execute("Swipe Left Detected");
        };

        gi.SwipeRight += (s, e) =>
        {
            DisplayAlert("Gesture Info", "Swipe Right Detected", "OK");
            ViewModel.SampleCommand.Execute("Swipe Right Detected");
        };

        this.Content = gi;
6
votes

FYI

SwipeView is available in Xamarin.Forms 4.4.

The SwipeView class also defines four events:

SwipeStarted is fired when a swipe starts. The SwipeStartedEventArgs object that accompanies this event has a SwipeDirection property, of type SwipeDirection.

SwipeChanging is fired as the swipe moves. The SwipeChangingEventArgs object that accompanies this event has a SwipeDirection property, of type SwipeDirection, and an Offset property of type double.

SwipeEnded is fired when a swipe ends. The SwipeEndedEventArgs object that accompanies this event has a SwipeDirection property, of type SwipeDirection.

CloseRequested is fired when the swipe items are closed. In addition, SwipeView defines a Close method, which closes the swipe items.

enter image description here

For more information about some new Xamarin Forms features visit this link.

2
votes

Building off of @Ranjith Kumar's solution, I came up with the following:

public delegate void SwipedEventHandler(ISwipeListener sender, SwipedEventArgs e);

public class SwipedEventArgs : EventArgs
{
    readonly double _x;
    public double X => _x;

    readonly double _y;
    public double Y => _y;

    readonly View _view;
    public View View => _view;

    public SwipedEventArgs(View view, double x, double y)
    {
        _view = view;
        _x = x;
        _y = y;
    }
}

public interface ISwipeListener
{
    event SwipedEventHandler SwipedDown;

    event SwipedEventHandler SwipedLeft;

    event SwipedEventHandler SwipedNothing;

    event SwipedEventHandler SwipedRight;

    event SwipedEventHandler SwipedUp;

    double TotalX
    {
        get;
    }

    double TotalY
    {
        get;
    }
}

public class SwipeListener : PanGestureRecognizer, ISwipeListener
{
    public event SwipedEventHandler SwipedDown;

    public event SwipedEventHandler SwipedLeft;

    public event SwipedEventHandler SwipedNothing;

    public event SwipedEventHandler SwipedRight;

    public event SwipedEventHandler SwipedUp;

    double _totalX = 0, _totalY = 0;

    public double TotalX => _totalX;

    public double TotalY => _totalY;

    readonly View _view;

    public SwipeListener(View view) : base()
    {
        _view = view;
        _view.GestureRecognizers.Add(this);
        PanUpdated += OnPanUpdated;
    }

    void OnPanUpdated(object sender, PanUpdatedEventArgs e)
    {
        switch (e.StatusType)
        {
            case GestureStatus.Running:
                try
                {
                    _totalX = e.TotalX;
                    _totalY = e.TotalY;
                }
                catch (Exception exception)
                {
                    Debug.WriteLine(exception.Message);
                }
                break;

            case GestureStatus.Completed:
                if (_totalX < 0 && Math.Abs(_totalX) > Math.Abs(_totalY))
                {
                    OnSwipedLeft(_totalX, _totalY);
                }
                else if (_totalX > 0 && _totalX > Math.Abs(_totalY))
                {
                    OnSwipedRight(_totalX, _totalY);
                }
                else if (_totalY < 0 && Math.Abs(_totalY) > Math.Abs(_totalX))
                {
                    OnSwipedUp(_totalX, _totalY);
                }
                else if (_totalY > 0 && _totalY > Math.Abs(_totalX))
                {
                    OnSwipedDown(_totalX, _totalY);
                }
                else OnSwipedNothing(_totalX, _totalY);
                break;

        }
    }

    protected virtual void OnSwipedDown(double x, double y)
        => SwipedDown?.Invoke(this, new SwipedEventArgs(_view, x, y));

    protected virtual void OnSwipedLeft(double x, double y)
        => SwipedLeft?.Invoke(this, new SwipedEventArgs(_view, x, y));

    protected virtual void OnSwipedNothing(double x, double y)
        => SwipedNothing?.Invoke(this, new SwipedEventArgs(_view, x, y));

    protected virtual void OnSwipedRight(double x, double y)
        => SwipedRight?.Invoke(this, new SwipedEventArgs(_view, x, y));

    protected virtual void OnSwipedUp(double x, double y)
        => SwipedUp?.Invoke(this, new SwipedEventArgs(_view, x, y));
}

The downside is you can't do anything while the swipe is performed, only after.

2
votes

Maybe that could help someone.

I had a problem: there was a ContentPage with scrollview and grid in it. All I need to do is to handle swipe left/right gestures. After searching through google/stackoverflow/github, I found a Nuget package called XamarinFormsGestures. That helped me a lot. All the instruction is inside the link. There is my code:

Vapolia.Lib.Ui.Gesture.SetSwipeLeftCommand(scrollviewgrid, 
new Command(() => { OnLeftSwipe(); })); // What's going on when left swiped.
Vapolia.Lib.Ui.Gesture.SetSwipeRightCommand(scrollviewgrid, 
new Command(() => { OnRightSwipe(); })); // What's going on when right swiped.