Xamarin.Forms: using the PanGestureRecognizer

- 3 mins

Using the PanGestureRecognizer

Recently I've blogged about Xamarin.Forms and how to create a XAML Behavior for enabling Multi-Touch gestures to generic elements and implementing a scale / pinch functionality.

Fortunately the framework provides three types of recognizer that greatly simplify the implementation:

Yesterday I decided to try the PanGestureRecognizer for extending the capabilities of the Behavior described in the previous post.

First of all, I added two Bindable properties in order to permit activation / deactivation of individual gestures (Bindable properties are equivalent to Dependency ones in UWP XAML)

#region IsScaleEnabled property

/// <summary>
/// Identifies the <see cref="IsScaleEnabledProperty" /> property.
/// </summary>
public static readonly BindableProperty IsScaleEnabledProperty =
    BindableProperty.Create<MultiTouchBehavior, bool>(w => w.IsScaleEnabled, default(bool));

/// <summary>
/// Identifies the <see cref="IsScaleEnabled" /> dependency / bindable property.
/// </summary>
public bool IsScaleEnabled
{
    get { return (bool)GetValue(IsScaleEnabledProperty); }
    set { SetValue(IsScaleEnabledProperty, value); }
}

#endregion

#region IsTranslateEnabled property

/// <summary>
/// Identifies the <see cref="IsTranslateEnabledProperty" /> property.
/// </summary>
public static readonly BindableProperty IsTranslateEnabledProperty =
    BindableProperty.Create<MultiTouchBehavior, bool>(w => w.IsTranslateEnabled, default(bool));

/// <summary>
/// Identifies the <see cref="IsTranslateEnabled" /> dependency / bindable property.
/// </summary>
public bool IsTranslateEnabled
{
    get { return (bool)GetValue(IsTranslateEnabledProperty); }
    set { SetValue(IsTranslateEnabledProperty, value); }
}

#endregion

In this way we can specify in our XAML what gestures are enabled:

...
<Image.Behaviors>
     <behaviors:MultiTouchBehavior IsScaleEnabled="True" IsTranslateEnabled="True" />
</Image.Behaviors>
...

Then I initialised the GestureRecognizers adding a new PanGestureRecognizer to the recognizers list:

/// <summary>
/// Initialise the Gesture Recognizers.
/// </summary>
private void InitialiseRecognizers()
{
    _panGestureRecognizer = new PanGestureRecognizer();
}

/// <summary>
/// Occurs when BindingContext is changed: used to initialise the Gesture Recognizers.
/// </summary>
/// <param name="sender">The sender object.</param>
/// <param name="e">The event parameters.</param>
private void AssociatedObjectBindingContextChanged(object sender, EventArgs e)
{
    _parent = _associatedObject.Parent as ContentView;
    _parent?.GestureRecognizers.Remove(_panGestureRecognizer);
    _parent?.GestureRecognizers.Add(_panGestureRecognizer);
}

And subscribed to the PanUpdated event in order to apply the translate transform:

/// <summary>
/// Initialise the events.
/// </summary>
private void InitializeEvents()
{
    CleanupEvents();

    _panGestureRecognizer.PanUpdated += OnPanUpdated;
}

The implementation of this event handler permits to update the X and Y coordinates of the element when a Pan gesture is detected:

/// <summary>
/// Implements Pan/Translate.
/// </summary>
/// <param name="sender">The sender object.</param>
/// <param name="e">The event parameters.</param>
private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
    if (_parent == null)
    {
        return;
    }

    if (!IsTranslateEnabled)
    {
        return;
    }

    switch (e.StatusType)
    {
        case GestureStatus.Running:
            _parent.Content.TranslationX = _xOffset + e.TotalX;
            _parent.Content.TranslationY = _yOffset + e.TotalY;
            break;

        case GestureStatus.Completed:
            _xOffset = _parent.Content.TranslationX;
            _yOffset = _parent.Content.TranslationY;
            break;
    }
}

Here we go: the sample app can now be deployed to the emulators and iOS / Android / Windows devices.

Just a couple of notes:

As usual, the latest source code is available for download on GitHub.

Davide Zordan

Davide Zordan

Senior Software Engineer

rss facebook twitter github gitlab youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora quora mastodon