Skip to content

Commit

Permalink
[A] PanGestureRecognizer will consistently send Completed event (xama…
Browse files Browse the repository at this point in the history
…rin#313)

* Adjust gallery page for reproduction

* [A] Forward OnTouchEvent to Listener...

...and end scrolling on Up.
  • Loading branch information
samhouts authored and Jason Smith committed Aug 30, 2016
1 parent 1b72501 commit ab0daa1
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 30 deletions.
91 changes: 62 additions & 29 deletions Xamarin.Forms.Controls/ControlGalleryPages/PanGestureGalleryPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,54 @@ namespace Xamarin.Forms.Controls
{
public class PanGestureGalleryPage : ContentPage
{
public class PanContainer : ContentView
public class PanCompleteArgs : EventArgs
{
public PanContainer ()
public PanCompleteArgs(string message) { Message = message; }
public string Message
{
var pan = new PanGestureRecognizer
{
TouchPoints = 1
};
get; private set;
}
}

pan.PanUpdated += (object s, PanUpdatedEventArgs e) =>
{
switch (e.StatusType) {
public class PanContainer : ContentView
{
double _x, _y;
double _currentScale = 1;

public EventHandler<PanCompleteArgs> PanCompleted;

case GestureStatus.Started: break;
public PanContainer()
{
GestureRecognizers.Add(GetPinch());
GestureRecognizers.Add(GetPan());
}

PanGestureRecognizer GetPan()
{
var pan = new PanGestureRecognizer();
pan.PanUpdated += (s, e) =>
{
switch (e.StatusType)
{
case GestureStatus.Running:
Content.TranslationX = e.TotalX;
Content.TranslationY = e.TotalY;
break;

default:
Content.TranslationX = Content.TranslationY = 0;
case GestureStatus.Completed:
_x = Content.TranslationX;
_y = Content.TranslationY;

PanCompleted?.Invoke(s, new PanCompleteArgs($"x: {_x}, y: {_y}"));
break;
}
};
return pan;
}

var pinch = new PinchGestureRecognizer ();
PinchGestureRecognizer GetPinch()
{
var pinch = new PinchGestureRecognizer();

double xOffset = 0;
double yOffset = 0;
Expand All @@ -43,14 +64,16 @@ public PanContainer ()
pinch.PinchUpdated += (sender, e) =>
{

if (e.Status == GestureStatus.Started) {
if (e.Status == GestureStatus.Started)
{
startScale = Content.Scale;
Content.AnchorX = Content.AnchorY = 0;
}
if (e.Status == GestureStatus.Running) {

if (e.Status == GestureStatus.Running)
{
_currentScale += (e.Scale - 1) * startScale;
_currentScale = Math.Max (1, _currentScale);
_currentScale = Math.Max(1, _currentScale);

var renderedX = Content.X + xOffset;
var deltaX = renderedX / Width;
Expand All @@ -65,32 +88,42 @@ public PanContainer ()
double targetX = xOffset - (originX * Content.Width) * (_currentScale - startScale);
double targetY = yOffset - (originY * Content.Height) * (_currentScale - startScale);

Content.TranslationX = targetX.Clamp (-Content.Width * (_currentScale - 1), 0);
Content.TranslationY = targetY.Clamp (-Content.Height * (_currentScale - 1), 0);
Content.TranslationX = targetX.Clamp(-Content.Width * (_currentScale - 1), 0);
Content.TranslationY = targetY.Clamp(-Content.Height * (_currentScale - 1), 0);

Content.Scale = _currentScale;
}
if (e.Status == GestureStatus.Completed) {

if (e.Status == GestureStatus.Completed)
{
xOffset = Content.TranslationX;
yOffset = Content.TranslationY;
}
};

GestureRecognizers.Add (pinch);

GestureRecognizers.Add (pan);
return pinch;
}

double _currentScale = 1;
}

public PanGestureGalleryPage ()
public PanGestureGalleryPage()
{
var image = new Image { Source = "http://placehold.it/2000x2000", BackgroundColor = Color.Gray, WidthRequest = 2000, HeightRequest = 2000, VerticalOptions = LayoutOptions.Center, HorizontalOptions = LayoutOptions.Center };
var box = new Image
{
BackgroundColor = Color.Gray,
WidthRequest = 2000,
HeightRequest = 2000,
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center
};

var label = new Label { Text = "Use two fingers to pinch. Use one finger to pan." };

var panme = new PanContainer { Content = image };
var panme = new PanContainer { Content = box };
panme.PanCompleted += (s, e) =>
{
label.Text = e.Message;
};

Content = new StackLayout { Children = { new Label { Text = "Use two fingers to pinch. Use one finger to pan." }, panme }, Padding = new Thickness (20) };
Content = new StackLayout { Children = { label, panme }, Padding = new Thickness(20) };
}
}
}
8 changes: 7 additions & 1 deletion Xamarin.Forms.Platform.Android/InnerGestureListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,18 @@ public InnerGestureListener(Func<int, bool> tapDelegate, Func<int, IEnumerable<T
}

// This is needed because GestureRecognizer callbacks can be delayed several hundred milliseconds
// which can result in the need to resurect this object if it has already been disposed. We dispose
// which can result in the need to resurrect this object if it has already been disposed. We dispose
// eagerly to allow easier garbage collection of the renderer
internal InnerGestureListener(IntPtr handle, JniHandleOwnership ownership) : base(handle, ownership)
{
}

internal void OnTouchEvent(MotionEvent e)
{
if (e.Action == MotionEventActions.Up)
EndScrolling();
}

bool GestureDetector.IOnDoubleTapListener.OnDoubleTap(MotionEvent e)
{
if (_tapDelegate == null || _tapGestureRecognizers == null)
Expand Down
3 changes: 3 additions & 0 deletions Xamarin.Forms.Platform.Android/VisualElementRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ bool IOnTouchListener.OnTouch(AView v, MotionEvent e)
ScaleGestureDetectorCompat.SetQuickScaleEnabled(_scaleDetector.Value, true);
handled = _scaleDetector.Value.OnTouchEvent(e);
}

_gestureListener?.OnTouchEvent(e);

return _gestureDetector.Value.OnTouchEvent(e) || handled;
}

Expand Down

0 comments on commit ab0daa1

Please sign in to comment.