Skip to content

Commit

Permalink
Add basic emitting of click event (#36616)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #36616

Changelog: [iOS][Internal] - Add basic emitting of click event

This diff adds the basic implementation of click event emitting, particularlly focused on ensuring clicks are only fired if the pointer interaction ends within the same tree "branch" of elements as which it started.

Reviewed By: yungsters

Differential Revision: D44148427

fbshipit-source-id: 9e91c32fe0e1ca8a5c50e72cd819625294e070f4
  • Loading branch information
vincentriemer authored and facebook-github-bot committed Apr 10, 2023
1 parent a6690bf commit 71506ce
Showing 1 changed file with 66 additions and 1 deletion.
67 changes: 66 additions & 1 deletion packages/react-native/React/Fabric/RCTSurfacePointerHandler.mm
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,26 @@ typedef NS_ENUM(NSInteger, RCTPointerEventType) {
RCTPointerEventTypeCancel,
};

static BOOL AllTouchesAreCancelledOrEnded(NSSet<UITouch *> *touches)
{
for (UITouch *touch in touches) {
if (touch.phase == UITouchPhaseBegan || touch.phase == UITouchPhaseMoved || touch.phase == UITouchPhaseStationary) {
return NO;
}
}
return YES;
}

static BOOL AnyTouchesChanged(NSSet<UITouch *> *touches)
{
for (UITouch *touch in touches) {
if (touch.phase == UITouchPhaseBegan || touch.phase == UITouchPhaseMoved) {
return YES;
}
}
return NO;
}

struct ActivePointer {
/*
* Pointer ID
Expand Down Expand Up @@ -349,7 +369,9 @@ static void UpdateActivePointerWithUITouch(
UIEvent *uiEvent,
UIView *rootComponentView)
{
activePointer.componentView = FindClosestFabricManagedTouchableView(uiTouch.view);
CGPoint location = [uiTouch locationInView:rootComponentView];
UIView *hitTestedView = [rootComponentView hitTest:location withEvent:nil];
activePointer.componentView = FindClosestFabricManagedTouchableView(hitTestedView);

activePointer.clientPoint = [uiTouch locationInView:rootComponentView];
activePointer.screenPoint = [rootComponentView convertPoint:activePointer.clientPoint
Expand Down Expand Up @@ -396,6 +418,22 @@ static BOOL IsAnyViewInPathListeningToEvent(NSOrderedSet<RCTReactTaggedView *> *
return NO;
}

/**
* Given an ActivePointer determine if it is still within the same event target tree as
* the one which initiated the pointer gesture.
*/
static BOOL IsPointerWithinInitialTree(ActivePointer activePointer)
{
NSOrderedSet<RCTReactTaggedView *> *initialViewSet =
GetTouchableViewsInPathToRoot(activePointer.initialComponentView);
for (RCTReactTaggedView *canidateTaggedView in initialViewSet) {
if (canidateTaggedView.tag == activePointer.componentView.tag) {
return YES;
}
}
return NO;
}

/**
* Surprisingly, `__unsafe_unretained id` pointers are not regular pointers
* and `std::hash<>` cannot hash them.
Expand Down Expand Up @@ -526,6 +564,8 @@ - (void)_registerTouches:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
activePointer.shouldLeaveWhenReleased = YES;
}

activePointer.initialComponentView = FindClosestFabricManagedTouchableView(touch.view);

UpdateActivePointerWithUITouch(activePointer, touch, event, _rootComponentView);

_activePointers.emplace(touch, activePointer);
Expand Down Expand Up @@ -618,6 +658,11 @@ - (void)_dispatchActivePointers:(std::vector<ActivePointer>)activePointers event
}
case RCTPointerEventTypeEnd: {
eventEmitter->onPointerUp(pointerEvent);

if (pointerEvent.isPrimary && pointerEvent.button == 0 && IsPointerWithinInitialTree(activePointer)) {
eventEmitter->onClick(pointerEvent);
}

if (activePointer.shouldLeaveWhenReleased) {
[self handleIncomingPointerEvent:pointerEvent onView:nil];
}
Expand All @@ -641,6 +686,12 @@ - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event

[self _registerTouches:touches withEvent:event];
[self _dispatchActivePointers:[self _activePointersFromTouches:touches] eventType:RCTPointerEventTypeStart];

if (self.state == UIGestureRecognizerStatePossible) {
self.state = UIGestureRecognizerStateBegan;
} else if (self.state == UIGestureRecognizerStateBegan) {
self.state = UIGestureRecognizerStateChanged;
}
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
Expand All @@ -649,6 +700,8 @@ - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event

[self _updateTouches:touches withEvent:event];
[self _dispatchActivePointers:[self _activePointersFromTouches:touches] eventType:RCTPointerEventTypeMove];

self.state = UIGestureRecognizerStateChanged;
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
Expand All @@ -658,6 +711,12 @@ - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
[self _updateTouches:touches withEvent:event];
[self _dispatchActivePointers:[self _activePointersFromTouches:touches] eventType:RCTPointerEventTypeEnd];
[self _unregisterTouches:touches];

if (AllTouchesAreCancelledOrEnded(event.allTouches)) {
self.state = UIGestureRecognizerStateEnded;
} else if (AnyTouchesChanged(event.allTouches)) {
self.state = UIGestureRecognizerStateChanged;
}
}

- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
Expand All @@ -667,6 +726,12 @@ - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
[self _updateTouches:touches withEvent:event];
[self _dispatchActivePointers:[self _activePointersFromTouches:touches] eventType:RCTPointerEventTypeCancel];
[self _unregisterTouches:touches];

if (AllTouchesAreCancelledOrEnded(event.allTouches)) {
self.state = UIGestureRecognizerStateCancelled;
} else if (AnyTouchesChanged(event.allTouches)) {
self.state = UIGestureRecognizerStateChanged;
}
}

- (void)reset
Expand Down

0 comments on commit 71506ce

Please sign in to comment.