15
15
@implementation RCTNativeAnimatedModule
16
16
{
17
17
RCTNativeAnimatedNodesManager *_nodesManager;
18
+
19
+ // Oparations called after views have been updated.
18
20
NSMutableArray <AnimatedOperation> *_operations;
21
+ // Operations called before views have been updated.
22
+ NSMutableArray <AnimatedOperation> *_preOperations;
19
23
}
20
24
21
25
RCT_EXPORT_MODULE ();
22
26
23
27
- (void )invalidate
24
28
{
25
29
[_nodesManager stopAnimationLoop ];
26
- }
27
-
28
- - (void )dealloc
29
- {
30
30
[self .bridge.eventDispatcher removeDispatchObserver: self ];
31
+ [self .bridge.uiManager removeUIManagerObserver: self ];
31
32
}
32
33
33
34
- (dispatch_queue_t )methodQueue
34
35
{
36
+ // This module needs to be on the same queue as the UIManager to avoid
37
+ // having to lock `_operations` and `_preOperations` since `uiManagerWillFlushUIBlocks`
38
+ // will be called from that queue.
35
39
return RCTGetUIManagerQueue ();
36
40
}
37
41
@@ -41,32 +45,34 @@ - (void)setBridge:(RCTBridge *)bridge
41
45
42
46
_nodesManager = [[RCTNativeAnimatedNodesManager alloc ] initWithUIManager: self .bridge.uiManager];
43
47
_operations = [NSMutableArray new ];
48
+ _preOperations = [NSMutableArray new ];
44
49
45
50
[bridge.eventDispatcher addDispatchObserver: self ];
51
+ [bridge.uiManager addUIManagerObserver: self ];
46
52
}
47
53
48
54
#pragma mark -- API
49
55
50
56
RCT_EXPORT_METHOD (createAnimatedNode:(nonnull NSNumber *)tag
51
57
config:(NSDictionary <NSString *, id > *)config)
52
58
{
53
- [_operations addObject : ^(RCTNativeAnimatedNodesManager *nodesManager) {
59
+ [self addOperationBlock : ^(RCTNativeAnimatedNodesManager *nodesManager) {
54
60
[nodesManager createAnimatedNode: tag config: config];
55
61
}];
56
62
}
57
63
58
64
RCT_EXPORT_METHOD (connectAnimatedNodes:(nonnull NSNumber *)parentTag
59
65
childTag:(nonnull NSNumber *)childTag)
60
66
{
61
- [_operations addObject : ^(RCTNativeAnimatedNodesManager *nodesManager) {
67
+ [self addOperationBlock : ^(RCTNativeAnimatedNodesManager *nodesManager) {
62
68
[nodesManager connectAnimatedNodes: parentTag childTag: childTag];
63
69
}];
64
70
}
65
71
66
72
RCT_EXPORT_METHOD (disconnectAnimatedNodes:(nonnull NSNumber *)parentTag
67
73
childTag:(nonnull NSNumber *)childTag)
68
74
{
69
- [_operations addObject : ^(RCTNativeAnimatedNodesManager *nodesManager) {
75
+ [self addOperationBlock : ^(RCTNativeAnimatedNodesManager *nodesManager) {
70
76
[nodesManager disconnectAnimatedNodes: parentTag childTag: childTag];
71
77
}];
72
78
}
@@ -76,44 +82,44 @@ - (void)setBridge:(RCTBridge *)bridge
76
82
config:(NSDictionary <NSString *, id > *)config
77
83
endCallback:(RCTResponseSenderBlock)callBack)
78
84
{
79
- [_operations addObject : ^(RCTNativeAnimatedNodesManager *nodesManager) {
85
+ [self addOperationBlock : ^(RCTNativeAnimatedNodesManager *nodesManager) {
80
86
[nodesManager startAnimatingNode: animationId nodeTag: nodeTag config: config endCallback: callBack];
81
87
}];
82
88
}
83
89
84
90
RCT_EXPORT_METHOD (stopAnimation:(nonnull NSNumber *)animationId)
85
91
{
86
- [_operations addObject : ^(RCTNativeAnimatedNodesManager *nodesManager) {
92
+ [self addOperationBlock : ^(RCTNativeAnimatedNodesManager *nodesManager) {
87
93
[nodesManager stopAnimation: animationId];
88
94
}];
89
95
}
90
96
91
97
RCT_EXPORT_METHOD (setAnimatedNodeValue:(nonnull NSNumber *)nodeTag
92
98
value:(nonnull NSNumber *)value)
93
99
{
94
- [_operations addObject : ^(RCTNativeAnimatedNodesManager *nodesManager) {
100
+ [self addOperationBlock : ^(RCTNativeAnimatedNodesManager *nodesManager) {
95
101
[nodesManager setAnimatedNodeValue: nodeTag value: value];
96
102
}];
97
103
}
98
104
99
105
RCT_EXPORT_METHOD (setAnimatedNodeOffset:(nonnull NSNumber *)nodeTag
100
106
offset:(nonnull NSNumber *)offset)
101
107
{
102
- [_operations addObject : ^(RCTNativeAnimatedNodesManager *nodesManager) {
108
+ [self addOperationBlock : ^(RCTNativeAnimatedNodesManager *nodesManager) {
103
109
[nodesManager setAnimatedNodeOffset: nodeTag offset: offset];
104
110
}];
105
111
}
106
112
107
113
RCT_EXPORT_METHOD (flattenAnimatedNodeOffset:(nonnull NSNumber *)nodeTag)
108
114
{
109
- [_operations addObject : ^(RCTNativeAnimatedNodesManager *nodesManager) {
115
+ [self addOperationBlock : ^(RCTNativeAnimatedNodesManager *nodesManager) {
110
116
[nodesManager flattenAnimatedNodeOffset: nodeTag];
111
117
}];
112
118
}
113
119
114
120
RCT_EXPORT_METHOD (extractAnimatedNodeOffset:(nonnull NSNumber *)nodeTag)
115
121
{
116
- [_operations addObject : ^(RCTNativeAnimatedNodesManager *nodesManager) {
122
+ [self addOperationBlock : ^(RCTNativeAnimatedNodesManager *nodesManager) {
117
123
[nodesManager extractAnimatedNodeOffset: nodeTag];
118
124
}];
119
125
}
@@ -122,38 +128,41 @@ - (void)setBridge:(RCTBridge *)bridge
122
128
viewTag:(nonnull NSNumber *)viewTag)
123
129
{
124
130
NSString *viewName = [self .bridge.uiManager viewNameForReactTag: viewTag];
125
- [_operations addObject : ^(RCTNativeAnimatedNodesManager *nodesManager) {
131
+ [self addOperationBlock : ^(RCTNativeAnimatedNodesManager *nodesManager) {
126
132
[nodesManager connectAnimatedNodeToView: nodeTag viewTag: viewTag viewName: viewName];
127
133
}];
128
134
}
129
135
130
136
RCT_EXPORT_METHOD (disconnectAnimatedNodeFromView:(nonnull NSNumber *)nodeTag
131
137
viewTag:(nonnull NSNumber *)viewTag)
132
138
{
133
- [_operations addObject: ^(RCTNativeAnimatedNodesManager *nodesManager) {
139
+ // Disconnecting a view also restores its default values so we have to make
140
+ // sure this happens before views get updated with their new props. This is
141
+ // why we enqueue this on the pre-operations queue.
142
+ [self addPreOperationBlock: ^(RCTNativeAnimatedNodesManager *nodesManager) {
134
143
[nodesManager disconnectAnimatedNodeFromView: nodeTag viewTag: viewTag];
135
144
}];
136
145
}
137
146
138
147
RCT_EXPORT_METHOD (dropAnimatedNode:(nonnull NSNumber *)tag)
139
148
{
140
- [_operations addObject : ^(RCTNativeAnimatedNodesManager *nodesManager) {
149
+ [self addOperationBlock : ^(RCTNativeAnimatedNodesManager *nodesManager) {
141
150
[nodesManager dropAnimatedNode: tag];
142
151
}];
143
152
}
144
153
145
154
RCT_EXPORT_METHOD (startListeningToAnimatedNodeValue:(nonnull NSNumber *)tag)
146
155
{
147
156
__weak id <RCTValueAnimatedNodeObserver> valueObserver = self;
148
- [_operations addObject : ^(RCTNativeAnimatedNodesManager *nodesManager) {
157
+ [self addOperationBlock : ^(RCTNativeAnimatedNodesManager *nodesManager) {
149
158
[nodesManager startListeningToAnimatedNodeValue: tag valueObserver: valueObserver];
150
159
}];
151
160
}
152
161
153
162
RCT_EXPORT_METHOD (stopListeningToAnimatedNodeValue:(nonnull NSNumber *)tag)
154
163
{
155
164
__weak id <RCTValueAnimatedNodeObserver> valueObserver = self;
156
- [_operations addObject : ^(RCTNativeAnimatedNodesManager *nodesManager) {
165
+ [self addOperationBlock : ^(RCTNativeAnimatedNodesManager *nodesManager) {
157
166
[nodesManager stopListeningToAnimatedNodeValue: tag valueObserver: valueObserver];
158
167
}];
159
168
}
@@ -162,7 +171,7 @@ - (void)setBridge:(RCTBridge *)bridge
162
171
eventName:(nonnull NSString *)eventName
163
172
eventMapping:(NSDictionary <NSString *, id > *)eventMapping)
164
173
{
165
- [_operations addObject : ^(RCTNativeAnimatedNodesManager *nodesManager) {
174
+ [self addOperationBlock : ^(RCTNativeAnimatedNodesManager *nodesManager) {
166
175
[nodesManager addAnimatedEventToView: viewTag eventName: eventName eventMapping: eventMapping];
167
176
}];
168
177
}
@@ -171,24 +180,45 @@ - (void)setBridge:(RCTBridge *)bridge
171
180
eventName:(nonnull NSString *)eventName
172
181
animatedNodeTag:(nonnull NSNumber *)animatedNodeTag)
173
182
{
174
- [_operations addObject : ^(RCTNativeAnimatedNodesManager *nodesManager) {
183
+ [self addOperationBlock : ^(RCTNativeAnimatedNodesManager *nodesManager) {
175
184
[nodesManager removeAnimatedEventFromView: viewTag eventName: eventName animatedNodeTag: animatedNodeTag];
176
185
}];
177
186
}
178
187
179
188
#pragma mark -- Batch handling
180
189
181
- - (void )batchDidComplete
190
+ - (void )addOperationBlock : (AnimatedOperation) operation
182
191
{
183
- NSArray *operations = _operations;
192
+ [_operations addObject: operation];
193
+ }
194
+
195
+ - (void )addPreOperationBlock : (AnimatedOperation)operation
196
+ {
197
+ [_preOperations addObject: operation];
198
+ }
199
+
200
+ - (void )uiManagerWillFlushUIBlocks : (RCTUIManager *)uiManager
201
+ {
202
+ if (_preOperations.count == 0 && _operations.count == 0 ) {
203
+ return ;
204
+ }
205
+
206
+ NSArray <AnimatedOperation> *preOperations = _preOperations;
207
+ NSArray <AnimatedOperation> *operations = _operations;
208
+ _preOperations = [NSMutableArray new ];
184
209
_operations = [NSMutableArray new ];
185
210
186
- dispatch_async ( dispatch_get_main_queue (), ^ {
187
- [operations enumerateObjectsUsingBlock: ^ (AnimatedOperation operation, NSUInteger i, BOOL *stop ) {
211
+ [uiManager prependUIBlock: ^(__unused RCTUIManager *manager, __unused NSDictionary < NSNumber *, UIView *> *viewRegistry) {
212
+ for (AnimatedOperation operation in preOperations ) {
188
213
operation (self->_nodesManager );
189
- }];
190
- [self ->_nodesManager updateAnimations ];
191
- });
214
+ }
215
+ }];
216
+
217
+ [uiManager addUIBlock: ^(__unused RCTUIManager *manager, __unused NSDictionary <NSNumber *, UIView *> *viewRegistry) {
218
+ for (AnimatedOperation operation in operations) {
219
+ operation (self->_nodesManager );
220
+ }
221
+ }];
192
222
}
193
223
194
224
#pragma mark -- Events
0 commit comments