Skip to content

Commit

Permalink
SwipeGestureRecognizer (xamarin#2727)
Browse files Browse the repository at this point in the history
* SwipeGesture

* Fix Build Error

* Remove unused var

* Update Xamarin.Forms.Controls.csproj

* Update Xamarin.Forms.ControlGallery.Android.csproj

* Update Xamarin.Forms.Maps.Android.csproj

* Update Xamarin.Forms.Core.UnitTests.csproj

* Update Xamarin.Forms.Platform.Android.AppLinks.csproj

* Update Xamarin.Forms.ControlGallery.Android.csproj

* Update Xamarin.Forms.Controls.csproj

* Update Xamarin.Forms.ControlGallery.Android.csproj

* Update GestureManager.cs
  • Loading branch information
seanyda authored and rmarinho committed May 28, 2018
1 parent 4bf2ffe commit 67f87df
Show file tree
Hide file tree
Showing 20 changed files with 519 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Xamarin.Build.Download.0.4.9\build\Xamarin.Build.Download.props" Condition="Exists('..\packages\Xamarin.Build.Download.0.4.9\build\Xamarin.Build.Download.props')" />
<PropertyGroup>
Expand Down Expand Up @@ -422,4 +422,4 @@
<Import Project="..\packages\Xamarin.Firebase.Common.60.1142.1\build\MonoAndroid80\Xamarin.Firebase.Common.targets" Condition="Exists('..\packages\Xamarin.Firebase.Common.60.1142.1\build\MonoAndroid80\Xamarin.Firebase.Common.targets')" />
<Import Project="..\packages\Xamarin.GooglePlayServices.Base.60.1142.1\build\MonoAndroid80\Xamarin.GooglePlayServices.Base.targets" Condition="Exists('..\packages\Xamarin.GooglePlayServices.Base.60.1142.1\build\MonoAndroid80\Xamarin.GooglePlayServices.Base.targets')" />
<Import Project="..\packages\Xamarin.Firebase.AppIndexing.60.1142.1\build\MonoAndroid80\Xamarin.Firebase.AppIndexing.targets" Condition="Exists('..\packages\Xamarin.Firebase.AppIndexing.60.1142.1\build\MonoAndroid80\Xamarin.Firebase.AppIndexing.targets')" />
</Project>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System;

namespace Xamarin.Forms.Controls
{
public class SwipeGestureGalleryPage : ContentPage
{
public class SwipeContainer : ContentView
{
public EventHandler SwipeLeft;
public EventHandler SwipeRight;
public EventHandler SwipeUp;
public EventHandler SwipeDown;

public SwipeContainer()
{
GestureRecognizers.Add(GetSwipeLeft());
GestureRecognizers.Add(GetSwipeRight());
GestureRecognizers.Add(GetSwipeUp());
GestureRecognizers.Add(GetSwipeDown());
}

SwipeGestureRecognizer GetSwipeLeft()
{
var swipe = new SwipeGestureRecognizer();
swipe.Direction = SwipeDirection.Left;
swipe.Swiped += (sender, args) => SwipeLeft?.Invoke(this, new EventArgs());
return swipe;
}

SwipeGestureRecognizer GetSwipeRight()
{
var swipe = new SwipeGestureRecognizer();
swipe.Direction = SwipeDirection.Right;
swipe.Swiped += (sender, args) => SwipeRight?.Invoke(this, new EventArgs());
return swipe;
}

SwipeGestureRecognizer GetSwipeUp()
{
var swipe = new SwipeGestureRecognizer();
swipe.Direction = SwipeDirection.Up;
swipe.Swiped += (sender, args) => SwipeUp?.Invoke(this, new EventArgs());
return swipe;
}

SwipeGestureRecognizer GetSwipeDown()
{
var swipe = new SwipeGestureRecognizer();
swipe.Direction = SwipeDirection.Down;
swipe.Swiped += (sender, args) => SwipeDown?.Invoke(this, new EventArgs());
return swipe;
}
}

public SwipeGestureGalleryPage()
{
var box = new Image
{
BackgroundColor = Color.Gray,
WidthRequest = 500,
HeightRequest = 500,
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center
};

var label = new Label { Text = "Use one finger and swipe inside the gray box." };

var swipeme = new SwipeContainer { Content = box };
swipeme.SwipeLeft += (sender, args) => label.Text = "You swiped left.";
swipeme.SwipeRight += (sender, args) => label.Text = "You swiped right.";
swipeme.SwipeUp += (sender, args) => label.Text = "You swiped up.";
swipeme.SwipeDown += (sender, args) => label.Text = "You swiped down.";

Content = new StackLayout { Children = { label, swipeme }, Padding = new Thickness(20) };
}
}
}
1 change: 1 addition & 0 deletions Xamarin.Forms.Controls/CoreGallery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ public override string ToString()
new GalleryPageFactory(() => new EntryCoreGalleryPage(), "Entry Gallery"),
new GalleryPageFactory(() => new NavBarTitleTestPage(), "Titles And Navbar Windows"),
new GalleryPageFactory(() => new PanGestureGalleryPage(), "Pan gesture Gallery"),
new GalleryPageFactory(() => new SwipeGestureGalleryPage(), "Swipe gesture Gallery"),
new GalleryPageFactory(() => new PinchGestureTestPage(), "Pinch gesture Gallery"),
new GalleryPageFactory(() => new AutomationIdGallery(), "AutomationID Gallery"),
new GalleryPageFactory(() => new LayoutPerformanceGallery(), "Layout Perf Gallery"),
Expand Down
4 changes: 2 additions & 2 deletions Xamarin.Forms.Controls/Xamarin.Forms.Controls.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
Expand Down Expand Up @@ -113,4 +113,4 @@

<Import Project="..\Xamarin.Forms.Controls.Issues\Xamarin.Forms.Controls.Issues.Shared\Xamarin.Forms.Controls.Issues.Shared.projitems" Label="Shared" />

</Project>
</Project>
87 changes: 87 additions & 0 deletions Xamarin.Forms.Core.UnitTests/SwipeGestureRecognizerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System;
using NUnit.Framework;

namespace Xamarin.Forms.Core.UnitTests
{
[TestFixture]
public class SwipeGestureRecognizerTests : BaseTestFixture
{
[Test]
public void Constructor()
{
var swipe = new SwipeGestureRecognizer();

Assert.AreEqual(null, swipe.Command);
Assert.AreEqual(null, swipe.CommandParameter);
Assert.AreEqual(100, swipe.Threshold);
}

[Test]
public void CallbackPassesParameter()
{
var view = new View();
var swipe = new SwipeGestureRecognizer();
swipe.CommandParameter = "Hello";

object result = null;
swipe.Command = new Command(o => result = o);

swipe.SendSwiped(view, SwipeDirection.Left);
Assert.AreEqual(result, swipe.CommandParameter);
}

[Test]
public void SwipedEventDirectionMatchesTotalXTest()
{
var view = new View();
var swipe = new SwipeGestureRecognizer();

SwipeDirection direction = SwipeDirection.Up;
swipe.Swiped += (object sender, SwipedEventArgs e) =>
{
direction = e.Direction;
};

((ISwipeGestureController)swipe).SendSwipe(view, totalX: -150, totalY: 10);
((ISwipeGestureController)swipe).DetectSwipe(view, SwipeDirection.Left);
Assert.AreEqual(SwipeDirection.Left, direction);
}

[Test]
public void SwipedEventDirectionMatchesTotalYTest()
{
var view = new View();
var swipe = new SwipeGestureRecognizer();

SwipeDirection direction = SwipeDirection.Left;
swipe.Swiped += (object sender, SwipedEventArgs e) =>
{
direction = e.Direction;
};

((ISwipeGestureController)swipe).SendSwipe(view, totalX: 10, totalY: -150);
((ISwipeGestureController)swipe).DetectSwipe(view, SwipeDirection.Up);
Assert.AreEqual(SwipeDirection.Up, direction);
}

[Test]
public void SwipeIgnoredIfBelowThresholdTest()
{
var view = new View();
var swipe = new SwipeGestureRecognizer();

// Specify a custom threshold for the test.
swipe.Threshold = 200;

bool detected = false;
swipe.Swiped += (object sender, SwipedEventArgs e) =>
{
detected = true;
};

((ISwipeGestureController)swipe).SendSwipe(view, totalX: 0, totalY: -175);
((ISwipeGestureController)swipe).DetectSwipe(view, SwipeDirection.Up);
Assert.IsFalse(detected);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
Expand Down Expand Up @@ -228,4 +228,4 @@
<LogicalName>Images/crimson.jpg</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Project>
</Project>
8 changes: 8 additions & 0 deletions Xamarin.Forms.Core/ISwipeGestureController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Xamarin.Forms
{
public interface ISwipeGestureController
{
void SendSwipe(Element sender, double totalX, double totalY);
bool DetectSwipe(View sender, SwipeDirection direction);
}
}
12 changes: 12 additions & 0 deletions Xamarin.Forms.Core/SwipeDirection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;
namespace Xamarin.Forms
{
[Flags]
public enum SwipeDirection
{
Right = 1,
Left = 2,
Up = 4,
Down = 8
}
}
95 changes: 95 additions & 0 deletions Xamarin.Forms.Core/SwipeGestureRecognizer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using System;
using System.Windows.Input;

namespace Xamarin.Forms
{
public sealed class SwipeGestureRecognizer : GestureRecognizer, ISwipeGestureController
{
// Default threshold in pixels before a swipe is detected.
const uint DefaultSwipeThreshold = 100;

double _totalX, _totalY;

public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(SwipeGestureRecognizer), null);

public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create("CommandParameter", typeof(object), typeof(SwipeGestureRecognizer), null);

public static readonly BindableProperty DirectionProperty = BindableProperty.Create("Direction", typeof(SwipeDirection), typeof(SwipeGestureRecognizer), default(SwipeDirection));

public static readonly BindableProperty ThresholdProperty = BindableProperty.Create("Threshold", typeof(uint), typeof(SwipeGestureRecognizer), DefaultSwipeThreshold);

public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}

public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}

public SwipeDirection Direction
{
get { return (SwipeDirection)GetValue(DirectionProperty); }
set { SetValue(DirectionProperty, value); }
}

public uint Threshold
{
get { return (uint)GetValue(ThresholdProperty); }
set { SetValue(ThresholdProperty, value); }
}

public event EventHandler<SwipedEventArgs> Swiped;

void ISwipeGestureController.SendSwipe(Element sender, double totalX, double totalY)
{
_totalX = totalX;
_totalY = totalY;
}

bool ISwipeGestureController.DetectSwipe(View sender, SwipeDirection direction)
{
var detected = false;
var threshold = Threshold;

if (direction.HasFlag(SwipeDirection.Left))
{
detected |= _totalX < -threshold;
}

if (direction.HasFlag(SwipeDirection.Right))
{
detected |= _totalX > threshold;
}

if (direction.HasFlag(SwipeDirection.Down))
{
detected |= _totalY > threshold;
}

if (direction.HasFlag(SwipeDirection.Up))
{
detected |= _totalY < -threshold;
}

if (detected)
{
SendSwiped(sender, direction);
}

return detected;
}

public void SendSwiped(View sender, SwipeDirection direction)
{
ICommand cmd = Command;
if (cmd != null && cmd.CanExecute(CommandParameter))
cmd.Execute(CommandParameter);

Swiped?.Invoke(sender, new SwipedEventArgs(CommandParameter, direction));
}
}
}
17 changes: 17 additions & 0 deletions Xamarin.Forms.Core/SwipedEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;

namespace Xamarin.Forms
{
public class SwipedEventArgs : EventArgs
{
public SwipedEventArgs(object parameter, SwipeDirection direction)
{
Parameter = parameter;
Direction = direction;
}

public object Parameter { get; private set; }

public SwipeDirection Direction { get; private set; }
}
}
4 changes: 2 additions & 2 deletions Xamarin.Forms.Maps.Android/Xamarin.Forms.Maps.Android.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Xamarin.Build.Download.0.4.9\build\Xamarin.Build.Download.props" Condition="Exists('..\packages\Xamarin.Build.Download.0.4.9\build\Xamarin.Build.Download.props')" />
<PropertyGroup>
Expand Down Expand Up @@ -201,4 +201,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Xamarin.Build.Download.0.4.9\build\Xamarin.Build.Download.props" Condition="Exists('..\packages\Xamarin.Build.Download.0.4.9\build\Xamarin.Build.Download.props')" />
<PropertyGroup>
Expand Down Expand Up @@ -155,4 +155,4 @@
<Import Project="..\packages\Xamarin.Firebase.Common.60.1142.1\build\MonoAndroid80\Xamarin.Firebase.Common.targets" Condition="Exists('..\packages\Xamarin.Firebase.Common.60.1142.1\build\MonoAndroid80\Xamarin.Firebase.Common.targets')" />
<Import Project="..\packages\Xamarin.GooglePlayServices.Base.60.1142.1\build\MonoAndroid80\Xamarin.GooglePlayServices.Base.targets" Condition="Exists('..\packages\Xamarin.GooglePlayServices.Base.60.1142.1\build\MonoAndroid80\Xamarin.GooglePlayServices.Base.targets')" />
<Import Project="..\packages\Xamarin.Firebase.AppIndexing.60.1142.1\build\MonoAndroid80\Xamarin.Firebase.AppIndexing.targets" Condition="Exists('..\packages\Xamarin.Firebase.AppIndexing.60.1142.1\build\MonoAndroid80\Xamarin.Firebase.AppIndexing.targets')" />
</Project>
</Project>
Loading

0 comments on commit 67f87df

Please sign in to comment.