@@ -396,6 +396,28 @@ static void UpdateActivePointerWithUITouch(
396396 activePointer.modifierFlags = uiEvent.modifierFlags ;
397397}
398398
399+ static BOOL IsViewListeningToEvent (RCTReactTaggedView *taggedView, ViewEvents::Offset eventType)
400+ {
401+ UIView *view = taggedView.view ;
402+ if (view && [view.class conformsToProtocol: @protocol (RCTComponentViewProtocol)]) {
403+ auto props = ((id <RCTComponentViewProtocol>)view).props ;
404+ if (SharedViewProps viewProps = std::dynamic_pointer_cast<ViewProps const >(props)) {
405+ return viewProps->events [eventType];
406+ }
407+ }
408+ return NO ;
409+ }
410+
411+ static BOOL IsAnyViewInPathListeningToEvent (NSOrderedSet <RCTReactTaggedView *> *viewPath, ViewEvents::Offset eventType)
412+ {
413+ for (RCTReactTaggedView *taggedView in viewPath) {
414+ if (IsViewListeningToEvent (taggedView, eventType)) {
415+ return YES ;
416+ }
417+ }
418+ return NO ;
419+ }
420+
399421/* *
400422 * Given an ActivePointer determine if it is still within the same event target tree as
401423 * the one which initiated the pointer gesture.
@@ -612,7 +634,8 @@ - (void)_dispatchActivePointers:(std::vector<ActivePointer>)activePointers event
612634{
613635 for (const auto &activePointer : activePointers) {
614636 PointerEvent pointerEvent = CreatePointerEventFromActivePointer (activePointer, eventType, _rootComponentView);
615- [self handleIncomingPointerEvent: pointerEvent onView: activePointer.componentView];
637+ NSOrderedSet <RCTReactTaggedView *> *eventPathViews = [self handleIncomingPointerEvent: pointerEvent
638+ onView: activePointer.componentView];
616639
617640 SharedTouchEventEmitter eventEmitter = GetTouchEmitterFromView (
618641 activePointer.componentView ,
@@ -625,7 +648,12 @@ - (void)_dispatchActivePointers:(std::vector<ActivePointer>)activePointers event
625648 break ;
626649 }
627650 case RCTPointerEventTypeMove: {
628- eventEmitter->onPointerMove (pointerEvent);
651+ BOOL hasMoveEventListeners =
652+ IsAnyViewInPathListeningToEvent (eventPathViews, ViewEvents::Offset::PointerMove) ||
653+ IsAnyViewInPathListeningToEvent (eventPathViews, ViewEvents::Offset::PointerMoveCapture);
654+ if (hasMoveEventListeners) {
655+ eventEmitter->onPointerMove (pointerEvent);
656+ }
629657 break ;
630658 }
631659 case RCTPointerEventTypeEnd: {
@@ -764,9 +792,11 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer
764792 PointerEvent event = CreatePointerEventFromIncompleteHoverData (
765793 pointerId, pointerType, clientLocation, screenLocation, offsetLocation, modifierFlags);
766794
767- [self handleIncomingPointerEvent: event onView: targetView];
795+ NSOrderedSet <RCTReactTaggedView *> *eventPathViews = [self handleIncomingPointerEvent: event onView: targetView];
768796 SharedTouchEventEmitter eventEmitter = GetTouchEmitterFromView (targetView, offsetLocation);
769- if (eventEmitter != nil ) {
797+ BOOL hasMoveEventListeners = IsAnyViewInPathListeningToEvent (eventPathViews, ViewEvents::Offset::PointerMove) ||
798+ IsAnyViewInPathListeningToEvent (eventPathViews, ViewEvents::Offset::PointerMoveCapture);
799+ if (eventEmitter != nil && hasMoveEventListeners) {
770800 eventEmitter->onPointerMove (event);
771801 }
772802}
@@ -801,9 +831,10 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer
801831
802832 // Out
803833 if (prevTargetView != nil && prevTargetTaggedView.tag != targetTaggedView.tag ) {
834+ BOOL shouldEmitOutEvent = IsAnyViewInPathListeningToEvent (currentlyHoveredViews, ViewEvents::Offset::PointerOut);
804835 SharedTouchEventEmitter eventEmitter =
805836 GetTouchEmitterFromView (prevTargetView, [_rootComponentView convertPoint: clientLocation toView: prevTargetView]);
806- if (eventEmitter != nil ) {
837+ if (shouldEmitOutEvent && eventEmitter != nil ) {
807838 eventEmitter->onPointerOut (event);
808839 }
809840 }
@@ -816,14 +847,20 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer
816847 // we reverse iterate (now from target to root), actually emitting the events.
817848 NSMutableOrderedSet <UIView *> *viewsToEmitLeaveEventsTo = [NSMutableOrderedSet orderedSet ];
818849
850+ BOOL hasParentLeaveListener = NO ;
819851 for (RCTReactTaggedView *taggedView in [currentlyHoveredViews reverseObjectEnumerator ]) {
820852 UIView *componentView = taggedView.view ;
821853
822- BOOL shouldEmitEvent = componentView != nil ;
854+ BOOL shouldEmitEvent = componentView != nil &&
855+ (hasParentLeaveListener || IsViewListeningToEvent (taggedView, ViewEvents::Offset::PointerLeave));
823856
824857 if (shouldEmitEvent && ![eventPathViews containsObject: taggedView]) {
825858 [viewsToEmitLeaveEventsTo addObject: componentView];
826859 }
860+
861+ if (shouldEmitEvent && !hasParentLeaveListener) {
862+ hasParentLeaveListener = YES ;
863+ }
827864 }
828865
829866 for (UIView *componentView in [viewsToEmitLeaveEventsTo reverseObjectEnumerator ]) {
@@ -836,9 +873,10 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer
836873
837874 // Over
838875 if (targetView != nil && prevTargetTaggedView.tag != targetTaggedView.tag ) {
876+ BOOL shouldEmitOverEvent = IsAnyViewInPathListeningToEvent (eventPathViews, ViewEvents::Offset::PointerOver);
839877 SharedTouchEventEmitter eventEmitter =
840878 GetTouchEmitterFromView (targetView, [_rootComponentView convertPoint: clientLocation toView: targetView]);
841- if (eventEmitter != nil ) {
879+ if (shouldEmitOverEvent && eventEmitter != nil ) {
842880 eventEmitter->onPointerOver (event);
843881 }
844882 }
@@ -850,10 +888,12 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer
850888 // or if one of its parents is listening in case those listeners care about the capturing phase. Adding the ability
851889 // for native to distinguish between capturing listeners and not could be an optimization to further reduce the number
852890 // of events we send to JS
891+ BOOL hasParentEnterListener = NO ;
853892 for (RCTReactTaggedView *taggedView in [eventPathViews reverseObjectEnumerator ]) {
854893 UIView *componentView = taggedView.view ;
855894
856- BOOL shouldEmitEvent = componentView != nil ;
895+ BOOL shouldEmitEvent = componentView != nil &&
896+ (hasParentEnterListener || IsViewListeningToEvent (taggedView, ViewEvents::Offset::PointerEnter));
857897
858898 if (shouldEmitEvent && ![currentlyHoveredViews containsObject: taggedView]) {
859899 SharedTouchEventEmitter eventEmitter =
@@ -862,6 +902,10 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer
862902 eventEmitter->onPointerEnter (event);
863903 }
864904 }
905+
906+ if (shouldEmitEvent && !hasParentEnterListener) {
907+ hasParentEnterListener = YES ;
908+ }
865909 }
866910
867911 [_currentlyHoveredViewsPerPointer setObject: eventPathViews forKey: @(pointerId)];
0 commit comments