diff --git a/src/Controls/src/Core/Platform/GestureManager/GesturePlatformManager.iOS.cs b/src/Controls/src/Core/Platform/GestureManager/GesturePlatformManager.iOS.cs index 411c9bda451d..180cce567809 100644 --- a/src/Controls/src/Core/Platform/GestureManager/GesturePlatformManager.iOS.cs +++ b/src/Controls/src/Core/Platform/GestureManager/GesturePlatformManager.iOS.cs @@ -20,7 +20,7 @@ class GesturePlatformManager : IDisposable { readonly NotifyCollectionChangedEventHandler _collectionChangedHandler; - readonly Dictionary _gestureRecognizers = new Dictionary(); + readonly Dictionary> _gestureRecognizers = new Dictionary>(); readonly List _interactions = new List(); readonly IPlatformViewHandler _handler; @@ -88,10 +88,16 @@ public void Dispose() tapGestureRecognizer.PropertyChanged -= OnTapGestureRecognizerPropertyChanged; } - if (PlatformView != null) - PlatformView.RemoveGestureRecognizer(kvp.Value); - kvp.Value.ShouldReceiveTouch = null; - kvp.Value.Dispose(); + foreach(var uiGestureRecognizer in kvp.Value) + { + if (uiGestureRecognizer is null) + continue; + + if (PlatformView != null) + PlatformView.RemoveGestureRecognizer(uiGestureRecognizer); + uiGestureRecognizer.ShouldReceiveTouch = null; + uiGestureRecognizer.Dispose(); + } } if (PlatformView != null && OperatingSystem.IsIOSVersionAtLeast(11)) @@ -221,7 +227,7 @@ public void Dispose() } - protected virtual UIGestureRecognizer? GetPlatformRecognizer(IGestureRecognizer recognizer) + protected virtual List? GetPlatformRecognizer(IGestureRecognizer recognizer) { if (recognizer == null) return null; @@ -229,45 +235,19 @@ public void Dispose() var weakRecognizer = new WeakReference(recognizer); var weakEventTracker = new WeakReference(this); - var tapGestureRecognizer = CreateTapRecognizer(weakEventTracker, weakRecognizer); if (tapGestureRecognizer != null) { - return tapGestureRecognizer; + return new List { tapGestureRecognizer }; } var pointerGestureRecognizer = recognizer as PointerGestureRecognizer; if (pointerGestureRecognizer != null && OperatingSystem.IsIOSVersionAtLeast(13)) { - var uiRecognizer = CreatePointerRecognizer(r => - { - if (weakRecognizer.Target is PointerGestureRecognizer pointerGestureRecognizer && - weakEventTracker.Target is GesturePlatformManager eventTracker && - eventTracker._handler?.VirtualView is View view && - eventTracker._handler?.MauiContext?.GetPlatformWindow() is UIWindow window) - { - var originPoint = r.LocationInView(eventTracker?.PlatformView); - var platformPointerArgs = new PlatformPointerEventArgs(r.View, r); - - switch (r.State) - { - case UIGestureRecognizerState.Began: - pointerGestureRecognizer.SendPointerEntered(view, (relativeTo) => CalculatePosition(relativeTo, originPoint, weakRecognizer, weakEventTracker), platformPointerArgs); - break; - case UIGestureRecognizerState.Changed: - pointerGestureRecognizer.SendPointerMoved(view, (relativeTo) => CalculatePosition(relativeTo, originPoint, weakRecognizer, weakEventTracker), platformPointerArgs); - break; - case UIGestureRecognizerState.Cancelled: - case UIGestureRecognizerState.Failed: - case UIGestureRecognizerState.Ended: - pointerGestureRecognizer.SendPointerExited(view, (relativeTo) => CalculatePosition(relativeTo, originPoint, weakRecognizer, weakEventTracker), platformPointerArgs); - break; - } - } - }); - return uiRecognizer; + var uiRecognizers = CreatePointerRecognizer(weakRecognizer, weakEventTracker); + return uiRecognizers; } var swipeRecognizer = recognizer as SwipeGestureRecognizer; @@ -283,7 +263,7 @@ public void Dispose() swipeGestureRecognizer.SendSwiped(view, direction); }); var uiRecognizer = CreateSwipeRecognizer(swipeRecognizer.Direction, returnAction, 1); - return uiRecognizer; + return new List { uiRecognizer }; } var pinchRecognizer = recognizer as IPinchGestureController; @@ -343,7 +323,7 @@ public void Dispose() } } }); - return uiRecognizer; + return new List { uiRecognizer }; } var panRecognizer = recognizer as PanGestureRecognizer; @@ -390,7 +370,7 @@ public void Dispose() } } }); - return uiRecognizer; + return new List { uiRecognizer }; } return null; @@ -424,9 +404,70 @@ UISwipeGestureRecognizer CreateSwipeRecognizer(SwipeDirection direction, Action< [SupportedOSPlatform("ios13.0")] [SupportedOSPlatform("maccatalyst13.0")] - CustomHoverGestureRecognizer CreatePointerRecognizer(Action action) + List CreatePointerRecognizer(WeakReference weakRecognizer, WeakReference weakEventTracker) { - var result = new CustomHoverGestureRecognizer(action); + bool exited = false; + + Action action = (pointerGesture) => + { + if (weakRecognizer.Target is PointerGestureRecognizer pointerGestureRecognizer && + weakEventTracker.Target is GesturePlatformManager eventTracker && + eventTracker._handler?.VirtualView is View view && + eventTracker._handler?.MauiContext?.GetPlatformWindow() is UIWindow window) + { + var originPoint = pointerGesture.LocationInView(eventTracker?.PlatformView); + var platformPointerArgs = new PlatformPointerEventArgs(pointerGesture.View, pointerGesture); + + switch (pointerGesture.State) + { + case UIGestureRecognizerState.Began: + exited = false; + if (pointerGesture is UIHoverGestureRecognizer) + pointerGestureRecognizer.SendPointerEntered(view, (relativeTo) => CalculatePosition(relativeTo, originPoint, weakRecognizer, weakEventTracker), platformPointerArgs); + else + pointerGestureRecognizer.SendPointerPressed(view, (relativeTo) => CalculatePosition(relativeTo, originPoint, weakRecognizer, weakEventTracker), platformPointerArgs); + break; + case UIGestureRecognizerState.Changed: + if (exited) + break; + + if (pointerGesture is UIHoverGestureRecognizer) + pointerGestureRecognizer.SendPointerMoved(view, (relativeTo) => CalculatePosition(relativeTo, originPoint, weakRecognizer, weakEventTracker), platformPointerArgs); + else + { + var bounds = eventTracker?.PlatformView?.Bounds; + if (bounds is not null && bounds.Value.Contains(originPoint)) + pointerGestureRecognizer.SendPointerMoved(view, (relativeTo) => CalculatePosition(relativeTo, originPoint, weakRecognizer, weakEventTracker), platformPointerArgs); + else + { + pointerGestureRecognizer.SendPointerExited(view, (relativeTo) => CalculatePosition(relativeTo, originPoint, weakRecognizer, weakEventTracker), platformPointerArgs); + exited = true; + pointerGesture.State = UIGestureRecognizerState.Ended; + break; + } + } + break; + case UIGestureRecognizerState.Cancelled: + case UIGestureRecognizerState.Failed: + case UIGestureRecognizerState.Ended: + if (exited) + break; + + if (pointerGesture is UIHoverGestureRecognizer) + pointerGestureRecognizer.SendPointerExited(view, (relativeTo) => CalculatePosition(relativeTo, originPoint, weakRecognizer, weakEventTracker), platformPointerArgs); + else + pointerGestureRecognizer.SendPointerReleased(view, (relativeTo) => CalculatePosition(relativeTo, originPoint, weakRecognizer, weakEventTracker), platformPointerArgs); + break; + } + } + }; + + var result = new List() + { + new UIHoverGestureRecognizer((gesture) => action.Invoke(gesture)) { ShouldRecognizeSimultaneously = (g, o) => true }, + new CustomPressGestureRecognizer((gesture) => action.Invoke(gesture)) { ShouldRecognizeSimultaneously = (g, o) => true } + + }; return result; } @@ -593,16 +634,6 @@ void LoadRecognizers() continue; } - var nativeRecognizer = GetPlatformRecognizer(recognizer); - - if (nativeRecognizer != null && PlatformView != null) - { - nativeRecognizer.ShouldReceiveTouch = _shouldReceiveTouch; - PlatformView.AddGestureRecognizer(nativeRecognizer); - - _gestureRecognizers[recognizer] = nativeRecognizer; - } - if (OperatingSystem.IsIOSVersionAtLeast(11) && recognizer is DragGestureRecognizer) { dragFound = true; @@ -627,6 +658,22 @@ void LoadRecognizers() PlatformView.AddInteraction(interaction); } } + + var nativeRecognizers = GetPlatformRecognizer(recognizer); + + if (nativeRecognizers is null) + continue; + + _gestureRecognizers[recognizer] = nativeRecognizers; + foreach (UIGestureRecognizer? nativeRecognizer in nativeRecognizers) + { + if (nativeRecognizer != null && PlatformView != null) + { + nativeRecognizer.ShouldReceiveTouch = _shouldReceiveTouch; + PlatformView.AddGestureRecognizer(nativeRecognizer); + + } + } } if (OperatingSystem.IsIOSVersionAtLeast(11)) @@ -649,19 +696,27 @@ void LoadRecognizers() for (int i = 0; i < toRemove.Count; i++) { IGestureRecognizer gestureRecognizer = toRemove[i]; - var uiRecognizer = _gestureRecognizers[gestureRecognizer]; + var uiRecognizers = _gestureRecognizers[gestureRecognizer]; _gestureRecognizers.Remove(gestureRecognizer); - if (PlatformView != null) - PlatformView.RemoveGestureRecognizer(uiRecognizer); - - if (TryGetTapGestureRecognizer(gestureRecognizer, out TapGestureRecognizer? tapGestureRecognizer) && - tapGestureRecognizer != null) + foreach (var uiRecognizer in uiRecognizers) { - gestureRecognizer.PropertyChanged -= OnTapGestureRecognizerPropertyChanged; - } + if (uiRecognizer is null) + continue; + + if (PlatformView != null) + { + PlatformView.RemoveGestureRecognizer(uiRecognizer); + } - uiRecognizer.Dispose(); + if (TryGetTapGestureRecognizer(gestureRecognizer, out TapGestureRecognizer? tapGestureRecognizer) && + tapGestureRecognizer != null) + { + gestureRecognizer.PropertyChanged -= OnTapGestureRecognizerPropertyChanged; + } + + uiRecognizer.Dispose(); + } } if (PlatformView != null && OperatingSystem.IsIOSVersionAtLeast(11)) diff --git a/src/Controls/src/Core/Platform/iOS/CustomHoverGestureRecognizer.cs b/src/Controls/src/Core/Platform/iOS/CustomHoverGestureRecognizer.cs deleted file mode 100644 index 3704025548dc..000000000000 --- a/src/Controls/src/Core/Platform/iOS/CustomHoverGestureRecognizer.cs +++ /dev/null @@ -1,43 +0,0 @@ -#nullable disable -using System; -using System.Runtime.Versioning; -using Foundation; -using ObjCRuntime; -using UIKit; -using PreserveAttribute = Microsoft.Maui.Controls.Internals.PreserveAttribute; - -namespace Microsoft.Maui.Controls.Platform.iOS; - -[SupportedOSPlatform("ios13.0")] -[SupportedOSPlatform("maccatalyst13.0")] -internal class CustomHoverGestureRecognizer : UIHoverGestureRecognizer -{ - NSObject _target; - - public CustomHoverGestureRecognizer(NSObject target, Selector action) : base(target, action) - { - _target = target; - } - - internal CustomHoverGestureRecognizer(Action action) - : this(new Callback(action), Selector.FromHandle(Selector.GetHandle("target:"))!) { } - - [Register("__UIHoverGestureRecognizer")] - class Callback : Token - { - Action action; - - internal Callback(Action action) - { - this.action = action; - } - - [Export("target:")] - [Preserve(Conditional = true)] - public void Activated(UIHoverGestureRecognizer sender) - { - if (OperatingSystem.IsIOSVersionAtLeast(13)) - action(sender); - } - } -} diff --git a/src/Controls/src/Core/Platform/iOS/CustomPressGestureRecognizer.cs b/src/Controls/src/Core/Platform/iOS/CustomPressGestureRecognizer.cs new file mode 100644 index 000000000000..0b5ec23f2a5d --- /dev/null +++ b/src/Controls/src/Core/Platform/iOS/CustomPressGestureRecognizer.cs @@ -0,0 +1,58 @@ +#nullable disable +using System; +using Foundation; +using ObjCRuntime; +using UIKit; +using PreserveAttribute = Microsoft.Maui.Controls.Internals.PreserveAttribute; + +namespace Microsoft.Maui.Controls.Platform.iOS; + +internal class CustomPressGestureRecognizer : UIGestureRecognizer +{ + NSObject _target; + + public CustomPressGestureRecognizer(NSObject target, Selector action) : base(target, action) + { + _target = target; + } + + public CustomPressGestureRecognizer(Action action) + : this(new Callback(action), Selector.FromHandle(Selector.GetHandle("target:"))!) { } + + [Register("__UIGestureRecognizer")] + class Callback : Token + { + Action action; + + internal Callback(Action action) + { + this.action = action; + } + + [Export("target:")] + [Preserve(Conditional = true)] + public void Activated(UIGestureRecognizer sender) + { + if (OperatingSystem.IsIOSVersionAtLeast(13)) + action(sender); + } + } + + public override void TouchesBegan(NSSet touches, UIEvent evt) + { + State = UIGestureRecognizerState.Began; + base.TouchesBegan(touches, evt); + } + + public override void TouchesEnded(NSSet touches, UIEvent evt) + { + State = UIGestureRecognizerState.Ended; + base.TouchesEnded(touches, evt); + } + + public override void TouchesMoved(NSSet touches, UIEvent evt) + { + State = UIGestureRecognizerState.Changed; + base.TouchesMoved(touches, evt); + } +}