-
Notifications
You must be signed in to change notification settings - Fork 25k
Native Animated - Restore default values when removing props on iOS #11819
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
eb5152f
a018a54
1649b1f
3c45755
0cbd66b
792288a
ae91a08
e94c8e1
ff5b2fe
4bbc66c
483bf36
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,23 +15,27 @@ | |
| @implementation RCTNativeAnimatedModule | ||
| { | ||
| RCTNativeAnimatedNodesManager *_nodesManager; | ||
|
|
||
| // Oparations called after views have been updated. | ||
| NSMutableArray<AnimatedOperation> *_operations; | ||
| // Operations called before views have been updated. | ||
| NSMutableArray<AnimatedOperation> *_preOperations; | ||
| } | ||
|
|
||
| RCT_EXPORT_MODULE(); | ||
|
|
||
| - (void)invalidate | ||
| { | ||
| [_nodesManager stopAnimationLoop]; | ||
| } | ||
|
|
||
| - (void)dealloc | ||
| { | ||
| [self.bridge.eventDispatcher removeDispatchObserver:self]; | ||
| [self.bridge.uiManager removeUIManagerObserver:self]; | ||
| } | ||
|
|
||
| - (dispatch_queue_t)methodQueue | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a comment saying this needs to be the UIManager queue because we access some data structures in uiManagerWillFlushUIBlocks which is also called on that queue
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually the only reason we need to run on the UIManager queue now is to avoid having to lock |
||
| { | ||
| // This module needs to be on the same queue as the UIManager to avoid | ||
| // having to lock `_operations` and `_preOperations` since `uiManagerWillFlushUIBlocks` | ||
| // will be called from that queue. | ||
| return RCTGetUIManagerQueue(); | ||
| } | ||
|
|
||
|
|
@@ -41,32 +45,34 @@ - (void)setBridge:(RCTBridge *)bridge | |
|
|
||
| _nodesManager = [[RCTNativeAnimatedNodesManager alloc] initWithUIManager:self.bridge.uiManager]; | ||
| _operations = [NSMutableArray new]; | ||
| _preOperations = [NSMutableArray new]; | ||
|
|
||
| [bridge.eventDispatcher addDispatchObserver:self]; | ||
| [bridge.uiManager addUIManagerObserver:self]; | ||
| } | ||
|
|
||
| #pragma mark -- API | ||
|
|
||
| RCT_EXPORT_METHOD(createAnimatedNode:(nonnull NSNumber *)tag | ||
| config:(NSDictionary<NSString *, id> *)config) | ||
| { | ||
| [_operations addObject:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [nodesManager createAnimatedNode:tag config:config]; | ||
| }]; | ||
| } | ||
|
|
||
| RCT_EXPORT_METHOD(connectAnimatedNodes:(nonnull NSNumber *)parentTag | ||
| childTag:(nonnull NSNumber *)childTag) | ||
| { | ||
| [_operations addObject:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [nodesManager connectAnimatedNodes:parentTag childTag:childTag]; | ||
| }]; | ||
| } | ||
|
|
||
| RCT_EXPORT_METHOD(disconnectAnimatedNodes:(nonnull NSNumber *)parentTag | ||
| childTag:(nonnull NSNumber *)childTag) | ||
| { | ||
| [_operations addObject:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [nodesManager disconnectAnimatedNodes:parentTag childTag:childTag]; | ||
| }]; | ||
| } | ||
|
|
@@ -76,44 +82,44 @@ - (void)setBridge:(RCTBridge *)bridge | |
| config:(NSDictionary<NSString *, id> *)config | ||
| endCallback:(RCTResponseSenderBlock)callBack) | ||
| { | ||
| [_operations addObject:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [nodesManager startAnimatingNode:animationId nodeTag:nodeTag config:config endCallback:callBack]; | ||
| }]; | ||
| } | ||
|
|
||
| RCT_EXPORT_METHOD(stopAnimation:(nonnull NSNumber *)animationId) | ||
| { | ||
| [_operations addObject:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [nodesManager stopAnimation:animationId]; | ||
| }]; | ||
| } | ||
|
|
||
| RCT_EXPORT_METHOD(setAnimatedNodeValue:(nonnull NSNumber *)nodeTag | ||
| value:(nonnull NSNumber *)value) | ||
| { | ||
| [_operations addObject:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [nodesManager setAnimatedNodeValue:nodeTag value:value]; | ||
| }]; | ||
| } | ||
|
|
||
| RCT_EXPORT_METHOD(setAnimatedNodeOffset:(nonnull NSNumber *)nodeTag | ||
| offset:(nonnull NSNumber *)offset) | ||
| { | ||
| [_operations addObject:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [nodesManager setAnimatedNodeOffset:nodeTag offset:offset]; | ||
| }]; | ||
| } | ||
|
|
||
| RCT_EXPORT_METHOD(flattenAnimatedNodeOffset:(nonnull NSNumber *)nodeTag) | ||
| { | ||
| [_operations addObject:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [nodesManager flattenAnimatedNodeOffset:nodeTag]; | ||
| }]; | ||
| } | ||
|
|
||
| RCT_EXPORT_METHOD(extractAnimatedNodeOffset:(nonnull NSNumber *)nodeTag) | ||
| { | ||
| [_operations addObject:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [nodesManager extractAnimatedNodeOffset:nodeTag]; | ||
| }]; | ||
| } | ||
|
|
@@ -122,38 +128,41 @@ - (void)setBridge:(RCTBridge *)bridge | |
| viewTag:(nonnull NSNumber *)viewTag) | ||
| { | ||
| NSString *viewName = [self.bridge.uiManager viewNameForReactTag:viewTag]; | ||
| [_operations addObject:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [nodesManager connectAnimatedNodeToView:nodeTag viewTag:viewTag viewName:viewName]; | ||
| }]; | ||
| } | ||
|
|
||
| RCT_EXPORT_METHOD(disconnectAnimatedNodeFromView:(nonnull NSNumber *)nodeTag | ||
| viewTag:(nonnull NSNumber *)viewTag) | ||
| { | ||
| [_operations addObject:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| // Disconnecting a view also restores its default values so we have to make | ||
| // sure this happens before views get updated with their new props. This is | ||
| // why we enqueue this on the pre-operations queue. | ||
| [self addPreOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [nodesManager disconnectAnimatedNodeFromView:nodeTag viewTag:viewTag]; | ||
| }]; | ||
| } | ||
|
|
||
| RCT_EXPORT_METHOD(dropAnimatedNode:(nonnull NSNumber *)tag) | ||
| { | ||
| [_operations addObject:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [nodesManager dropAnimatedNode:tag]; | ||
| }]; | ||
| } | ||
|
|
||
| RCT_EXPORT_METHOD(startListeningToAnimatedNodeValue:(nonnull NSNumber *)tag) | ||
| { | ||
| __weak id<RCTValueAnimatedNodeObserver> valueObserver = self; | ||
| [_operations addObject:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [nodesManager startListeningToAnimatedNodeValue:tag valueObserver:valueObserver]; | ||
| }]; | ||
| } | ||
|
|
||
| RCT_EXPORT_METHOD(stopListeningToAnimatedNodeValue:(nonnull NSNumber *)tag) | ||
| { | ||
| __weak id<RCTValueAnimatedNodeObserver> valueObserver = self; | ||
| [_operations addObject:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [nodesManager stopListeningToAnimatedNodeValue:tag valueObserver:valueObserver]; | ||
| }]; | ||
| } | ||
|
|
@@ -162,7 +171,7 @@ - (void)setBridge:(RCTBridge *)bridge | |
| eventName:(nonnull NSString *)eventName | ||
| eventMapping:(NSDictionary<NSString *, id> *)eventMapping) | ||
| { | ||
| [_operations addObject:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [nodesManager addAnimatedEventToView:viewTag eventName:eventName eventMapping:eventMapping]; | ||
| }]; | ||
| } | ||
|
|
@@ -171,24 +180,45 @@ - (void)setBridge:(RCTBridge *)bridge | |
| eventName:(nonnull NSString *)eventName | ||
| animatedNodeTag:(nonnull NSNumber *)animatedNodeTag) | ||
| { | ||
| [_operations addObject:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { | ||
| [nodesManager removeAnimatedEventFromView:viewTag eventName:eventName animatedNodeTag:animatedNodeTag]; | ||
| }]; | ||
| } | ||
|
|
||
| #pragma mark -- Batch handling | ||
|
|
||
| - (void)batchDidComplete | ||
| - (void)addOperationBlock:(AnimatedOperation)operation | ||
| { | ||
| [_operations addObject:operation]; | ||
| } | ||
|
|
||
| - (void)addPreOperationBlock:(AnimatedOperation)operation | ||
| { | ||
| [_preOperations addObject:operation]; | ||
| } | ||
|
|
||
| - (void)uiManagerWillFlushUIBlocks:(RCTUIManager *)uiManager | ||
| { | ||
| NSArray *operations = _operations; | ||
| if (_preOperations.count == 0 && _operations.count == 0) { | ||
| return; | ||
| } | ||
|
|
||
| NSArray<AnimatedOperation> *preOperations = _preOperations; | ||
| NSArray<AnimatedOperation> *operations = _operations; | ||
| _preOperations = [NSMutableArray new]; | ||
| _operations = [NSMutableArray new]; | ||
|
|
||
| dispatch_async(dispatch_get_main_queue(), ^{ | ||
| [operations enumerateObjectsUsingBlock:^(AnimatedOperation operation, NSUInteger i, BOOL *stop) { | ||
| operation(self->_nodesManager); | ||
| }]; | ||
| [self->_nodesManager updateAnimations]; | ||
| }); | ||
| [uiManager prependUIBlock:^(__unused RCTUIManager *manager, __unused NSDictionary<NSNumber *, UIView *> *viewRegistry) { | ||
| for (AnimatedOperation operation in preOperations) { | ||
| operation(_nodesManager); | ||
| } | ||
| }]; | ||
|
|
||
| [uiManager addUIBlock:^(__unused RCTUIManager *manager, __unused NSDictionary<NSNumber *, UIView *> *viewRegistry) { | ||
| for (AnimatedOperation operation in operations) { | ||
| operation(_nodesManager); | ||
| } | ||
| }]; | ||
| } | ||
|
|
||
| #pragma mark -- Events | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there are props that were previously set, but now are no longer set -- that is, if the old value of
_propsDictionaryhas keys that wouldn't be inprops(in the old code) -- should we set those entries in_propsDictionaryto[NSNull null]?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A props node always keep the same props, if the props change we create a new one. See https://github.com/facebook/react-native/blob/master/Libraries/Animated/src/AnimatedImplementation.js#L1777 which is called from componentWillReceiveProps.