Skip to content

Commit

Permalink
[MacCatalyst] Implement PointerPressed and PointerReleased (#16925)
Browse files Browse the repository at this point in the history
  • Loading branch information
rachelkang committed Nov 27, 2023
1 parent 01afe33 commit 6b32433
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 102 deletions.
Expand Up @@ -20,7 +20,7 @@ class GesturePlatformManager : IDisposable
{
readonly NotifyCollectionChangedEventHandler _collectionChangedHandler;

readonly Dictionary<IGestureRecognizer, UIGestureRecognizer> _gestureRecognizers = new Dictionary<IGestureRecognizer, UIGestureRecognizer>();
readonly Dictionary<IGestureRecognizer, List<UIGestureRecognizer?>> _gestureRecognizers = new Dictionary<IGestureRecognizer, List<UIGestureRecognizer?>>();
readonly List<INativeObject> _interactions = new List<INativeObject>();
readonly IPlatformViewHandler _handler;

Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -221,53 +227,27 @@ public void Dispose()

}

protected virtual UIGestureRecognizer? GetPlatformRecognizer(IGestureRecognizer recognizer)
protected virtual List<UIGestureRecognizer?>? GetPlatformRecognizer(IGestureRecognizer recognizer)
{
if (recognizer == null)
return null;

var weakRecognizer = new WeakReference(recognizer);
var weakEventTracker = new WeakReference(this);


var tapGestureRecognizer = CreateTapRecognizer(weakEventTracker, weakRecognizer);

if (tapGestureRecognizer != null)
{
return tapGestureRecognizer;
return new List<UIGestureRecognizer?> { 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;
Expand All @@ -283,7 +263,7 @@ public void Dispose()
swipeGestureRecognizer.SendSwiped(view, direction);
});
var uiRecognizer = CreateSwipeRecognizer(swipeRecognizer.Direction, returnAction, 1);
return uiRecognizer;
return new List<UIGestureRecognizer?> { uiRecognizer };
}

var pinchRecognizer = recognizer as IPinchGestureController;
Expand Down Expand Up @@ -343,7 +323,7 @@ public void Dispose()
}
}
});
return uiRecognizer;
return new List<UIGestureRecognizer?> { uiRecognizer };
}

var panRecognizer = recognizer as PanGestureRecognizer;
Expand Down Expand Up @@ -390,7 +370,7 @@ public void Dispose()
}
}
});
return uiRecognizer;
return new List<UIGestureRecognizer?> { uiRecognizer };
}

return null;
Expand Down Expand Up @@ -424,9 +404,70 @@ UISwipeGestureRecognizer CreateSwipeRecognizer(SwipeDirection direction, Action<

[SupportedOSPlatform("ios13.0")]
[SupportedOSPlatform("maccatalyst13.0")]
CustomHoverGestureRecognizer CreatePointerRecognizer(Action<UIHoverGestureRecognizer> action)
List<UIGestureRecognizer?> CreatePointerRecognizer(WeakReference weakRecognizer, WeakReference weakEventTracker)
{
var result = new CustomHoverGestureRecognizer(action);
bool exited = false;

Action<UIGestureRecognizer> 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<UIGestureRecognizer?>()
{
new UIHoverGestureRecognizer((gesture) => action.Invoke(gesture)) { ShouldRecognizeSimultaneously = (g, o) => true },
new CustomPressGestureRecognizer((gesture) => action.Invoke(gesture)) { ShouldRecognizeSimultaneously = (g, o) => true }

};
return result;
}

Expand Down Expand Up @@ -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;
Expand All @@ -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))
Expand All @@ -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))
Expand Down
43 changes: 0 additions & 43 deletions src/Controls/src/Core/Platform/iOS/CustomHoverGestureRecognizer.cs

This file was deleted.

58 changes: 58 additions & 0 deletions 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<UIGestureRecognizer> action)
: this(new Callback(action), Selector.FromHandle(Selector.GetHandle("target:"))!) { }

[Register("__UIGestureRecognizer")]
class Callback : Token
{
Action<UIGestureRecognizer> action;

internal Callback(Action<UIGestureRecognizer> 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);
}
}

0 comments on commit 6b32433

Please sign in to comment.