# Multi-Touch Behaviors
XAML Behaviors implementing Multi-Touch Manipulation (Gestures) and Inertia.
Xamarin Forms Behavior uses code from original Xamarin.Forms samples: https://github.com/xamarin/xamarin-forms-samples/tree/master/WorkingWithGestures
Archived projects targeting Silverlight, WPF and Windows Phone 7.x, 8.x available on CodePlex: http://multitouch.codeplex.com/.
## Xamarin.Forms: using the PanGestureRecognizer
<p style="text-align: center;"><img class="size-medium wp-image-7904 aligncenter" src="https://davide.dev/wp-content/uploads/2016/02/Using-PanGestureRecognizer.png" alt="Using the PanGestureRecognizer" width="256" height="500"></p>
<p style="text-align: justify;">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.</p>
<p style="text-align: justify;">Fortunately the framework provides <a href="https://developer.xamarin.com/guides/xamarin-forms/user-interface/gestures/" target="_blank" rel="noopener noreferrer">three types of recognizer</a> that greatly simplify the implementation:</p>
<ul>
<li style="text-align: justify;"><strong>PinchGestureRecognizer</strong> allows user interactions for zoom / scale functionalities;</li>
<li style="text-align: justify;"><strong>PanGestureRecognizer</strong> enables pan / translate transformations;</li>
<li style="text-align: justify;"><strong>TapGestureRecognizer</strong> detects tap events.</li>
</ul>
<p style="text-align: justify;">Yesterday I decided to try the <strong>PanGestureRecognizer </strong>for extending the capabilities of the Behavior described in the previous post.</p>
<p style="text-align: justify;">First of all, I added two <em>Bindable</em> properties in order to permit activation / deactivation of individual gestures (<em>Bindable</em> properties are equivalent to <em>Dependency</em> ones in UWP XAML)</p>
<pre class="lang:default decode:true" title="IsTranslateEnabled and IsScaleEnabled Bindable properties">#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</pre>
<p style="text-align: justify;">In this way we can specify in our XAML what gestures are enabled:</p>
<pre class="lang:default decode:true ">...
<Image.Behaviors>
<behaviors:MultiTouchBehavior IsScaleEnabled="True" IsTranslateEnabled="True" />
</Image.Behaviors>
...</pre>
<p style="text-align: justify;">Then I initialised the GestureRecognizers adding a new <strong>PanGestureRecognizer </strong>to the recognizers list:</p>
<pre class="lang:default decode:true ">/// <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);
}</pre>
<p style="text-align: justify;">And subscribed to the <strong>PanUpdated</strong> event in order to apply the translate transform:</p>
<pre class="lang:default decode:true ">/// <summary>
/// Initialise the events.
/// </summary>
private void InitializeEvents()
{
CleanupEvents();
_panGestureRecognizer.PanUpdated += OnPanUpdated;
}</pre>
<p style="text-align: justify;">The implementation of this event handler permits to update the X and Y coordinates of the element when a Pan gesture is detected:</p>
<pre class="lang:default decode:true " title="PanUpdated event handler implementation">/// <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;
}
}</pre>
<p style="text-align: justify;">Here we go: the sample app can now be deployed to the emulators and iOS / Android / Windows devices.</p>
<p style="text-align: justify;">Just a couple of notes:</p>
<ul>
<li style="text-align: justify;">deployment to iOS required this <a href="http://codeworks.it/blog/?p=242" target="_blank" rel="noopener noreferrer">workaround</a> to work properly since the new sample app uses different assemblies;</li>
<li style="text-align: justify;">Project has been updated to Visual Studio 2019 and Xamarin.Forms 3.6.0.</li>
</ul>