Adding a Pan Gesture Recognizer

PDF for offline use
Sample Code:
Related APIs:

Let us know how you feel about this


0/250

last updated: 2016-01

The pan gesture is used for detecting dragging and is implemented with the PanGestureRecognizer class. A common scenario for the pan gesture is to horizontally and vertically drag an image, so that all of the image content can be viewed when it's being displayed in a viewport smaller than the image dimensions. This is accomplished by moving the image within the viewport, and is demonstrated in this article.

Overview

To make a user interface element draggable with the pan gesture, create a PanGestureRecognizer instance, handle the PanUpdated event, and add the new gesture recognizer to the GestureRecognizers collection on the user interface element. The following code example shows a PanGestureRecognizer attached to an Image element:

var panGesture = new PanGestureRecognizer();
panGesture.PanUpdated += (s, e) => {
  // Handle the pan
};
image.GestureRecognizers.Add(panGesture);

This can also be achieved in XAML, as shown in the following code example:

<Image Source="MonoMonkey.jpg">
  <Image.GestureRecognizers>
    <PanGestureRecognizer PanUpdated="OnPanUpdated" />
  </Image.GestureRecognizers>
</Image>

The code for the OnPanUpdated event handler is then added to the code-behind file:

void OnPanUpdated (object sender, PanUpdatedEventArgs e)
{
  // Handle the pan
}

Correct panning on Android requires the Xamarin.Forms 2.1.0-pre1 NuGet package at a minimum.

Creating a Pan Container

This section contains a generalized helper class that performs freeform panning, which is typically suited to navigating within images or maps. Handling the pan gesture to perform a drag operation requires some math to transform the user interface. This math is used to drag only within the bounds of the wrapped user interface element. The following code example shows the PanContainer class:

public class PanContainer : ContentView
{
  double x, y;

  public PanContainer ()
  {
    // Set PanGestureRecognizer.TouchPoints to control the
    // number of touch points needed to pan
    var panGesture = new PanGestureRecognizer ();
    panGesture.PanUpdated += OnPanUpdated;
    GestureRecognizers.Add (panGesture);
  }

  void OnPanUpdated (object sender, PanUpdatedEventArgs e)
  {
    ...
  }
}

This class can be wrapped around a user interface element so that the pan gesture will drag the wrapped user interface element. The following XAML code example shows the PanContainer wrapping an Image element:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:PanGesture"
             x:Class="PanGesture.HomePage">
    <ContentPage.Content>
        <AbsoluteLayout>
            <local:PanContainer>
                <Image Source="MonoMonkey.jpg" WidthRequest="1024" HeightRequest="768" />
            </local:PanContainer>
        </AbsoluteLayout>
    </ContentPage.Content>
</ContentPage>

The following code example shows how the PanContainer wraps an Image element in a C# page:

public class HomePageCS : ContentPage
{
  public HomePageCS ()
  {
    Content = new AbsoluteLayout {
      Padding = new Thickness (20),
      Children = {
        new PanContainer {
          Content = new Image {
            Source = ImageSource.FromFile ("MonoMonkey.jpg"),
            WidthRequest = 1024,
            HeightRequest = 768
          }
        }
      }
    };
  }
}

In both examples, the WidthRequest and HeightRequest properties are set to the width and height values of the image being displayed.

When the Image element receives a pan gesture, the displayed image will be dragged. The drag is performed by the PanContainer.OnPanUpdated method, which is shown in the following code example:

void OnPanUpdated (object sender, PanUpdatedEventArgs e)
{
  switch (e.StatusType) {
  case GestureStatus.Running:
    // Translate and ensure we don't pan beyond the wrapped user interface element bounds.
    Content.TranslationX =
      Math.Max (Math.Min (0, x + e.TotalX), -Math.Abs (Content.Width - App.ScreenWidth));
    Content.TranslationY =
      Math.Max (Math.Min (0, y + e.TotalY), -Math.Abs (Content.Height - App.ScreenHeight));
    break;

  case GestureStatus.Completed:
    // Store the translation applied during the pan
    x = Content.TranslationX;
    y = Content.TranslationY;
    break;
  }
}

This method updates the viewable content of the wrapped user interface element, based on the user's pan gesture. This is achieved by using the values of the TotalX and TotalY properties of the PanUpdatedEventArgs instance to calculate the direction and distance of the pan. The App.ScreenWidth and App.ScreenHeight properties provide the height and width of the viewport, and are set to the screen width and screen height values of the device by the respective platform-specific projects. The wrapped user element is then dragged by setting its TranslationX and TranslationY properties to the calculated values.

When panning content in an element that does not occupy the full screen, the height and width of the viewport can be obtained from the element's Height and Width properties.

Displaying high-resolution images can greatly increase an app's memory footprint. Therefore, they should only be created when required and should be released as soon as the app no longer requires them. For more information, see Optimize Image Resources.

Summary

The pan gesture is used for detecting dragging and is implemented with the PanGestureRecognizer class.

Xamarin Workbook

If it's not already installed, install the Xamarin Workbooks app first. The workbook file should download automatically, but if it doesn't, just click to start the workbook download manually.