From 137bb5538dc8cb69db9769b607b6d0a62ace13ac Mon Sep 17 00:00:00 2001 From: Kevin Petit Date: Wed, 16 Mar 2022 20:53:54 +0100 Subject: [PATCH] Ensure that the GestureDetector is disposed --- .../Android/SwipeAwareContainerRenderer.cs | 120 ++++++++++++------ 1 file changed, 82 insertions(+), 38 deletions(-) diff --git a/src/Calendar.Plugin/Android/SwipeAwareContainerRenderer.cs b/src/Calendar.Plugin/Android/SwipeAwareContainerRenderer.cs index 2fd385d..e035c25 100644 --- a/src/Calendar.Plugin/Android/SwipeAwareContainerRenderer.cs +++ b/src/Calendar.Plugin/Android/SwipeAwareContainerRenderer.cs @@ -5,74 +5,118 @@ using Xamarin.Plugin.Calendar.Controls; using Xamarin.Forms; using Xamarin.Forms.Platform.Android; +using View = Xamarin.Forms.View; [assembly: ExportRenderer(typeof(SwipeAwareContainer), typeof(SwipeAwareContainerRenderer))] namespace Xamarin.Plugin.Calendar.Android { - internal class SwipeAwareContainerRenderer : ViewRenderer, GestureDetector.IOnGestureListener + internal class SwipeAwareContainerRenderer : ViewRenderer { private const int SwipeDistanceThreshold = 50; private const int SwipeVelocityThreshold = 20; - private readonly GestureDetector _gestureDetector; + private GestureDetector _gestureDetector; + private GestureDetector.IOnGestureListener _gestureListener; + private bool _isDisposed; public SwipeAwareContainerRenderer(Context context) : base(context) { - _gestureDetector = new GestureDetector(context, this); + } + + protected override void OnElementChanged(ElementChangedEventArgs e) + { + base.OnElementChanged(e); + + if (e.OldElement != null) + { + DisposeGestureDetectorAndListener(); + } + + if (e.NewElement != null) + { + _gestureListener = new InnerGestureListener(Element as SwipeAwareContainer); + _gestureDetector = new GestureDetector(Context, _gestureListener); + } } public override bool OnInterceptTouchEvent(MotionEvent ev) { + if (_isDisposed) + return false; + if (Element is SwipeAwareContainer element && !element.SwipeDetectionDisabled) - _gestureDetector.OnTouchEvent(ev); + _gestureDetector?.OnTouchEvent(ev); return base.OnInterceptTouchEvent(ev); } - public bool OnFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) + protected override void Dispose(bool disposing) { - if (!(Element is SwipeAwareContainer element)) - return false; + if (_isDisposed) + return; - float distanceX = e2.GetX() - e1.GetX(); - float distanceY = e2.GetY() - e1.GetY(); + _isDisposed = true; - if (Math.Abs(distanceX) > Math.Abs(distanceY)) + if (disposing) { - if (Math.Abs(distanceX) > SwipeDistanceThreshold && Math.Abs(velocityX) > SwipeVelocityThreshold) - { - if (distanceX > 0) - element.OnSwipeRight(); - else - element.OnSwipeLeft(); - - return true; - } + DisposeGestureDetectorAndListener(); } - else - { - if (Math.Abs(distanceY) > SwipeDistanceThreshold && Math.Abs(velocityY) > SwipeVelocityThreshold) - { - if (distanceY > 0) - element.OnSwipeDown(); - else - element.OnSwipeUp(); - return true; - } - } + base.Dispose(disposing); + } + + private void DisposeGestureDetectorAndListener() + { + _gestureDetector?.Dispose(); + _gestureDetector = null; - return false; + _gestureListener?.Dispose(); + _gestureListener = null; } - #region Unused gestures + private class InnerGestureListener : GestureDetector.SimpleOnGestureListener + { + private SwipeAwareContainer SwipeAwareContainer { get; } + + public InnerGestureListener(SwipeAwareContainer swipeAwareContainer) + { + SwipeAwareContainer = swipeAwareContainer; + } + + public override bool OnFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) + { + if (SwipeAwareContainer == null) + return false; + + float distanceX = e2.GetX() - e1.GetX(); + float distanceY = e2.GetY() - e1.GetY(); - public bool OnDown(MotionEvent e) => false; - public void OnLongPress(MotionEvent e) { } - public bool OnScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) => false; - public void OnShowPress(MotionEvent e) { } - public bool OnSingleTapUp(MotionEvent e) => false; + if (Math.Abs(distanceX) > Math.Abs(distanceY)) + { + if (Math.Abs(distanceX) > SwipeDistanceThreshold && Math.Abs(velocityX) > SwipeVelocityThreshold) + { + if (distanceX > 0) + SwipeAwareContainer.OnSwipeRight(); + else + SwipeAwareContainer.OnSwipeLeft(); - #endregion + return true; + } + } + else + { + if (Math.Abs(distanceY) > SwipeDistanceThreshold && Math.Abs(velocityY) > SwipeVelocityThreshold) + { + if (distanceY > 0) + SwipeAwareContainer.OnSwipeDown(); + else + SwipeAwareContainer.OnSwipeUp(); + return true; + } + } + + return false; + } + } } } \ No newline at end of file