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