зеркало из https://github.com/DeGsoft/maui-linux.git
218 строки
5.1 KiB
C#
218 строки
5.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using Android.Content;
|
|
using Android.Support.V4.View;
|
|
using Android.Views;
|
|
|
|
namespace Xamarin.Forms.Platform.Android
|
|
{
|
|
internal class GestureManager : IDisposable
|
|
{
|
|
IVisualElementRenderer _renderer;
|
|
readonly Lazy<ScaleGestureDetector> _scaleDetector;
|
|
readonly Lazy<GestureDetector> _tapAndPanAndSwipeDetector;
|
|
|
|
bool _disposed;
|
|
bool _inputTransparent;
|
|
bool _isEnabled;
|
|
|
|
VisualElement Element => _renderer?.Element;
|
|
|
|
View View => _renderer?.Element as View;
|
|
|
|
global::Android.Views.View Control => _renderer?.View;
|
|
|
|
public GestureManager(IVisualElementRenderer renderer)
|
|
{
|
|
_renderer = renderer;
|
|
_renderer.ElementChanged += OnElementChanged;
|
|
|
|
_tapAndPanAndSwipeDetector = new Lazy<GestureDetector>(InitializeTapAndPanAndSwipeDetector);
|
|
_scaleDetector = new Lazy<ScaleGestureDetector>(InitializeScaleDetector);
|
|
}
|
|
|
|
public bool OnTouchEvent(MotionEvent e)
|
|
{
|
|
if (Control == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!_isEnabled || _inputTransparent)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!DetectorsValid())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var eventConsumed = false;
|
|
if (ViewHasPinchGestures())
|
|
{
|
|
eventConsumed = _scaleDetector.Value.OnTouchEvent(e);
|
|
}
|
|
|
|
if (!ViewHasPinchGestures() || !_scaleDetector.Value.IsInProgress)
|
|
eventConsumed = _tapAndPanAndSwipeDetector.Value.OnTouchEvent(e) || eventConsumed;
|
|
|
|
return eventConsumed;
|
|
}
|
|
|
|
public class TapAndPanGestureDetector : GestureDetector
|
|
{
|
|
readonly InnerGestureListener _listener;
|
|
public TapAndPanGestureDetector(Context context, InnerGestureListener listener) : base(context, listener)
|
|
{
|
|
_listener = listener;
|
|
InitializeLongPressSettings();
|
|
}
|
|
|
|
void InitializeLongPressSettings()
|
|
{
|
|
// Right now this just disables long press, since we don't support a long press gesture
|
|
// in Forms. If we ever do, we'll need to selectively enable it, probably by hooking into the
|
|
// InnerGestureListener and listening for the addition of any long press gesture recognizers.
|
|
// (since a long press will prevent a pan gesture from starting, we can't just leave support for it
|
|
// on by default).
|
|
// Also, since the property is virtual we shouldn't just set it from the constructor.
|
|
|
|
IsLongpressEnabled = false;
|
|
}
|
|
|
|
public override bool OnTouchEvent(MotionEvent ev)
|
|
{
|
|
if (base.OnTouchEvent(ev))
|
|
return true;
|
|
|
|
if (ev.Action == MotionEventActions.Up)
|
|
_listener.EndScrolling();
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
bool DetectorsValid()
|
|
{
|
|
// Make sure we're not testing for gestures on old motion events after our
|
|
// detectors have already been disposed
|
|
|
|
if (_scaleDetector.IsValueCreated && _scaleDetector.Value.Handle == IntPtr.Zero)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (_tapAndPanAndSwipeDetector.IsValueCreated && _tapAndPanAndSwipeDetector.Value.Handle == IntPtr.Zero)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
GestureDetector InitializeTapAndPanAndSwipeDetector()
|
|
{
|
|
var context = Control.Context;
|
|
var listener = new InnerGestureListener(new TapGestureHandler(() => View, () =>
|
|
{
|
|
if (Element is View view)
|
|
return view.GetChildElements(Point.Zero) ?? new List<GestureElement>();
|
|
|
|
return new List<GestureElement>();
|
|
}),
|
|
new PanGestureHandler(() => View, context.FromPixels),
|
|
new SwipeGestureHandler(() => View, context.FromPixels));
|
|
|
|
return new TapAndPanGestureDetector(context, listener);
|
|
}
|
|
|
|
ScaleGestureDetector InitializeScaleDetector()
|
|
{
|
|
var context = Control.Context;
|
|
var listener = new InnerScaleListener(new PinchGestureHandler(() => View), context.FromPixels);
|
|
var detector = new ScaleGestureDetector(context, listener, Control.Handler);
|
|
ScaleGestureDetectorCompat.SetQuickScaleEnabled(detector, true);
|
|
|
|
return detector;
|
|
}
|
|
|
|
bool ViewHasPinchGestures()
|
|
{
|
|
return View != null && View.GestureRecognizers.OfType<PinchGestureRecognizer>().Any();
|
|
}
|
|
|
|
void OnElementChanged(object sender, VisualElementChangedEventArgs e)
|
|
{
|
|
if (e.OldElement != null)
|
|
{
|
|
e.OldElement.PropertyChanged -= OnElementPropertyChanged;
|
|
}
|
|
|
|
if (e.NewElement != null)
|
|
{
|
|
e.NewElement.PropertyChanged += OnElementPropertyChanged;
|
|
}
|
|
|
|
UpdateInputTransparent();
|
|
UpdateIsEnabled();
|
|
}
|
|
|
|
void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
{
|
|
if (e.PropertyName == VisualElement.InputTransparentProperty.PropertyName)
|
|
UpdateInputTransparent();
|
|
else if (e.PropertyName == VisualElement.IsEnabledProperty.PropertyName)
|
|
UpdateIsEnabled();
|
|
}
|
|
|
|
protected void Dispose(bool disposing)
|
|
{
|
|
if (_disposed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_disposed = true;
|
|
|
|
if (disposing)
|
|
{
|
|
if (Element != null)
|
|
{
|
|
Element.PropertyChanged -= OnElementPropertyChanged;
|
|
}
|
|
|
|
_renderer = null;
|
|
}
|
|
}
|
|
|
|
void UpdateInputTransparent()
|
|
{
|
|
if (Element == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_inputTransparent = Element.InputTransparent;
|
|
}
|
|
|
|
void UpdateIsEnabled()
|
|
{
|
|
if (Element == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_isEnabled = Element.IsEnabled;
|
|
}
|
|
}
|
|
}
|