[A] PanGestureRecognizer will consistently send Completed event (#313)

* Adjust gallery page for reproduction

* [A] Forward OnTouchEvent to Listener...

...and end scrolling on Up.
This commit is contained in:
Samantha Houts 2016-08-30 11:14:13 -07:00 коммит произвёл Jason Smith
Родитель 1b7250167f
Коммит ab0daa1947
3 изменённых файлов: 73 добавлений и 31 удалений

Просмотреть файл

@ -8,33 +8,54 @@ namespace Xamarin.Forms.Controls
{
public class PanGestureGalleryPage : ContentPage
{
public class PanCompleteArgs : EventArgs
{
public PanCompleteArgs(string message) { Message = message; }
public string Message
{
get; private set;
}
}
public class PanContainer : ContentView
{
public PanContainer ()
double _x, _y;
double _currentScale = 1;
public EventHandler<PanCompleteArgs> PanCompleted;
public PanContainer()
{
var pan = new PanGestureRecognizer
GestureRecognizers.Add(GetPinch());
GestureRecognizers.Add(GetPan());
}
PanGestureRecognizer GetPan()
{
var pan = new PanGestureRecognizer();
pan.PanUpdated += (s, e) =>
{
TouchPoints = 1
};
pan.PanUpdated += (object s, PanUpdatedEventArgs e) =>
{
switch (e.StatusType) {
case GestureStatus.Started: break;
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;
@ -43,14 +64,16 @@ namespace Xamarin.Forms.Controls
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;
@ -65,32 +88,42 @@ namespace Xamarin.Forms.Controls
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 panme = new PanContainer { Content = image };
var label = new Label { Text = "Use two fingers to pinch. Use one finger to pan." };
Content = new StackLayout { Children = { new Label { Text = "Use two fingers to pinch. Use one finger to pan." }, panme }, Padding = new Thickness (20) };
var panme = new PanContainer { Content = box };
panme.PanCompleted += (s, e) =>
{
label.Text = e.Message;
};
Content = new StackLayout { Children = { label, panme }, Padding = new Thickness(20) };
}
}
}

Просмотреть файл

@ -38,12 +38,18 @@ namespace Xamarin.Forms.Platform.Android
}
// 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)

Просмотреть файл

@ -98,6 +98,9 @@ namespace Xamarin.Forms.Platform.Android
ScaleGestureDetectorCompat.SetQuickScaleEnabled(_scaleDetector.Value, true);
handled = _scaleDetector.Value.OnTouchEvent(e);
}
_gestureListener?.OnTouchEvent(e);
return _gestureDetector.Value.OnTouchEvent(e) || handled;
}