Receive the onUserDrivenAnimationEnded event in JS (#45383)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/45383

This is the second step required to fix the onTouchMove event in the new architecture.

In this change, we are retrieving the list of nodes that are connected by the animation, and we are sending an event to the nodes so that we can trigger the commit.

## Changelog
[iOS][Added] - retrieve the tags of the nodes connected by the animation and send them to JS

Reviewed By: sammy-SC

Differential Revision: D59524617

fbshipit-source-id: 584317afa8e4cf0ad9f98f38e4e5d436c5fe3ac5
This commit is contained in:
Riccardo Cipolleschi
2024-07-17 09:22:39 -07:00
committed by Facebook GitHub Bot
parent 7af743236f
commit fd748ae84c
3 changed files with 60 additions and 1 deletions
@@ -87,6 +87,8 @@ NS_ASSUME_NONNULL_BEGIN
- (void)stopListeningToAnimatedNodeValue:(NSNumber *)tag;
- (NSSet<NSNumber *> *)getTagsOfConnectedNodesFrom:(NSNumber *)tag andEvent:(NSString *)eventName;
@end
NS_ASSUME_NONNULL_END
@@ -479,6 +479,24 @@ static NSString *RCTNormalizeAnimatedEventName(NSString *eventName)
[self stopAnimationLoopIfNeeded];
}
- (NSSet<NSNumber *> *)getTagsOfConnectedNodesFrom:(NSNumber *)tag andEvent:(NSString *)eventName
{
NSMutableSet<NSNumber *> *tags = [NSMutableSet new];
NSString *key = [NSString stringWithFormat:@"%@%@", tag, RCTNormalizeAnimatedEventName(eventName)];
NSArray<RCTEventAnimation *> *eventAnimations = _eventDrivers[key];
for (RCTEventAnimation *animation in eventAnimations) {
NSNumber *nodeTag = [animation.valueNode nodeTag];
if (nodeTag) {
[tags addObject:nodeTag];
}
for (NSNumber *childNodeKey in [animation.valueNode childNodes]) {
[tags addObject:childNodeKey];
}
}
return tags;
}
#pragma mark-- Updates
- (void)updateAnimations
@@ -25,6 +25,11 @@ typedef void (^AnimatedOperation)(RCTNativeAnimatedNodesManager *nodesManager);
NSMutableArray<AnimatedOperation> *_operations;
// Operations called before views have been updated.
NSMutableArray<AnimatedOperation> *_preOperations;
NSSet<NSString *> *_userDrivenAnimationEndedEvents;
// TODO: Remove this when https://github.com/facebook/react-native/pull/45457 lands
BOOL _shouldEmitEvent;
}
RCT_EXPORT_MODULE();
@@ -39,6 +44,8 @@ RCT_EXPORT_MODULE();
if (self = [super init]) {
_operations = [NSMutableArray new];
_preOperations = [NSMutableArray new];
_userDrivenAnimationEndedEvents = [NSSet setWithArray:@[ @"onScrollEnded" ]];
_shouldEmitEvent = NO;
}
return self;
}
@@ -364,7 +371,7 @@ RCT_EXPORT_METHOD(queueAndExecuteBatchedOperations : (NSArray *)operationsAndArg
- (NSArray<NSString *> *)supportedEvents
{
return @[ @"onAnimatedValueUpdate" ];
return @[ @"onAnimatedValueUpdate", @"onUserDrivenAnimationEnded" ];
}
- (void)animatedNode:(RCTValueAnimatedNode *)node didUpdateValue:(CGFloat)value
@@ -372,12 +379,44 @@ RCT_EXPORT_METHOD(queueAndExecuteBatchedOperations : (NSArray *)operationsAndArg
[self sendEventWithName:@"onAnimatedValueUpdate" body:@{@"tag" : node.nodeTag, @"value" : @(value)}];
}
// TODO: Remove this when https://github.com/facebook/react-native/pull/45457 lands
- (void)startObserving
{
[super startObserving];
_shouldEmitEvent = YES;
}
- (void)stopObserving
{
[super stopObserving];
_shouldEmitEvent = NO;
}
// ----
- (void)userDrivenAnimationEnded:(NSArray<NSNumber *> *)nodes
{
if (!_shouldEmitEvent) {
return;
}
[self sendEventWithName:@"onUserDrivenAnimationEnded" body:@{@"tags" : nodes}];
}
- (void)eventDispatcherWillDispatchEvent:(id<RCTEvent>)event
{
// Events can be dispatched from any queue so we have to make sure handleAnimatedEvent
// is run from the main queue.
RCTExecuteOnMainQueue(^{
[self->_nodesManager handleAnimatedEvent:event];
if ([self->_userDrivenAnimationEndedEvents containsObject:event.eventName]) {
NSSet<NSNumber *> *tags = [self->_nodesManager getTagsOfConnectedNodesFrom:event.viewTag
andEvent:event.eventName];
if (tags.count > 0) {
[self userDrivenAnimationEnded:[tags allObjects]];
}
}
});
}