This repository has been archived by the owner on Nov 12, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
927 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
177 changes: 177 additions & 0 deletions
177
src/Xfx.Controls.Droid/Forms.Internals/GestureManager.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
using System; | ||
using System.ComponentModel; | ||
using System.Linq; | ||
using Android.Support.V4.View; | ||
using Android.Views; | ||
using Xamarin.Forms; | ||
using Xamarin.Forms.Platform.Android; | ||
using View = Xamarin.Forms.View; | ||
|
||
namespace Xfx.Controls.Droid.Forms.Internals | ||
{ | ||
internal class GestureManager : IDisposable | ||
{ | ||
IVisualElementRenderer _renderer; | ||
readonly Lazy<GestureDetector> _tapAndPanDetector; | ||
readonly Lazy<ScaleGestureDetector> _scaleDetector; | ||
|
||
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; | ||
|
||
_tapAndPanDetector = new Lazy<GestureDetector>(InitializeTapAndPanDetector); | ||
_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); | ||
} | ||
|
||
eventConsumed = _tapAndPanDetector.Value.OnTouchEvent(e) || eventConsumed; | ||
|
||
return eventConsumed; | ||
} | ||
|
||
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 (_tapAndPanDetector.IsValueCreated && _tapAndPanDetector.Value.Handle == IntPtr.Zero) | ||
{ | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
GestureDetector InitializeTapAndPanDetector() | ||
{ | ||
var context = Control.Context; | ||
var listener = new InnerGestureListener(new TapGestureHandler(() => View), | ||
new PanGestureHandler(() => View, context.FromPixels)); | ||
|
||
return new GestureDetector(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; | ||
} | ||
} | ||
} |
Oops, something went wrong.