react-native-reanimated 3.0.0-rc.4 → 3.0.0-rc.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Common/cpp/LayoutAnimations/LayoutAnimationsProxy.cpp +97 -15
- package/Common/cpp/LayoutAnimations/LayoutAnimationsProxy.h +32 -8
- package/Common/cpp/NativeModules/NativeReanimatedModule.cpp +16 -1
- package/Common/cpp/NativeModules/NativeReanimatedModule.h +8 -1
- package/Common/cpp/NativeModules/NativeReanimatedModuleSpec.cpp +17 -0
- package/Common/cpp/NativeModules/NativeReanimatedModuleSpec.h +8 -0
- package/Common/cpp/ReanimatedRuntime/ReanimatedRuntime.cpp +2 -1
- package/Common/cpp/ReanimatedRuntime/ReanimatedRuntime.h +1 -0
- package/Common/cpp/Tools/RuntimeDecorator.cpp +2 -1
- package/android/CMakeLists.txt +1 -0
- package/android/build.gradle +9 -1
- package/android/src/fabric/java/com/swmansion/reanimated/NativeProxy.java +16 -25
- package/android/src/main/cpp/LayoutAnimations.cpp +42 -50
- package/android/src/main/cpp/LayoutAnimations.h +17 -3
- package/android/src/main/cpp/NativeProxy.cpp +55 -6
- package/android/src/main/java/com/swmansion/reanimated/NodesManager.java +1 -1
- package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/AnimationsManager.java +208 -223
- package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/LayoutAnimations.java +7 -5
- package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/NativeMethodsHolder.java +5 -3
- package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/ViewHierarchyObserver.java +1 -1
- package/android/src/paper/java/com/swmansion/reanimated/NativeProxy.java +20 -7
- package/android/src/reactNativeVersionPatch/nativeHierarchyManager/62/com/swmansion/reanimated/layoutReanimation/ReanimatedNativeHierarchyManager.java +8 -44
- package/android/src/reactNativeVersionPatch/nativeHierarchyManager/latest/com/swmansion/reanimated/layoutReanimation/ReanimatedNativeHierarchyManager.java +15 -61
- package/ios/LayoutReanimation/REAAnimationsManager.h +18 -8
- package/ios/LayoutReanimation/REAAnimationsManager.m +197 -162
- package/ios/LayoutReanimation/REAUIManager.mm +63 -70
- package/ios/native/NativeProxy.mm +55 -48
- package/lib/commonjs/createAnimatedComponent.js +26 -26
- package/lib/commonjs/createAnimatedComponent.js.map +1 -1
- package/lib/commonjs/reanimated2/NativeReanimated/NativeReanimated.js +4 -0
- package/lib/commonjs/reanimated2/NativeReanimated/NativeReanimated.js.map +1 -1
- package/lib/commonjs/reanimated2/core.js +9 -9
- package/lib/commonjs/reanimated2/core.js.map +1 -1
- package/lib/commonjs/reanimated2/globals.d.js.map +1 -1
- package/lib/commonjs/reanimated2/jestUtils.js +17 -9
- package/lib/commonjs/reanimated2/jestUtils.js.map +1 -1
- package/lib/commonjs/reanimated2/layoutReanimation/LayoutAnimationRepository.js +23 -62
- package/lib/commonjs/reanimated2/layoutReanimation/LayoutAnimationRepository.js.map +1 -1
- package/lib/module/createAnimatedComponent.js +27 -26
- package/lib/module/createAnimatedComponent.js.map +1 -1
- package/lib/module/reanimated2/NativeReanimated/NativeReanimated.js +4 -0
- package/lib/module/reanimated2/NativeReanimated/NativeReanimated.js.map +1 -1
- package/lib/module/reanimated2/core.js +7 -9
- package/lib/module/reanimated2/core.js.map +1 -1
- package/lib/module/reanimated2/globals.d.js.map +1 -1
- package/lib/module/reanimated2/jestUtils.js +17 -9
- package/lib/module/reanimated2/jestUtils.js.map +1 -1
- package/lib/module/reanimated2/layoutReanimation/LayoutAnimationRepository.js +22 -61
- package/lib/module/reanimated2/layoutReanimation/LayoutAnimationRepository.js.map +1 -1
- package/package.json +2 -2
- package/src/createAnimatedComponent.tsx +48 -39
- package/src/reanimated2/NativeReanimated/NativeReanimated.ts +15 -0
- package/src/reanimated2/core.ts +19 -10
- package/src/reanimated2/globals.d.ts +10 -6
- package/src/reanimated2/jestUtils.ts +14 -6
- package/src/reanimated2/layoutReanimation/LayoutAnimationRepository.ts +24 -50
- package/lib/commonjs/reanimated2/layoutReanimation/defaultAnimations/Default.js +0 -55
- package/lib/commonjs/reanimated2/layoutReanimation/defaultAnimations/Default.js.map +0 -1
- package/lib/module/reanimated2/layoutReanimation/defaultAnimations/Default.js +0 -40
- package/lib/module/reanimated2/layoutReanimation/defaultAnimations/Default.js.map +0 -1
- package/src/reanimated2/layoutReanimation/defaultAnimations/Default.ts +0 -49
|
@@ -5,28 +5,38 @@
|
|
|
5
5
|
#import <React/UIView+Private.h>
|
|
6
6
|
#import <React/UIView+React.h>
|
|
7
7
|
|
|
8
|
-
@interface REAAnimationsManager ()
|
|
9
|
-
|
|
10
8
|
typedef NS_ENUM(NSInteger, FrameConfigType) { EnteringFrame, ExitingFrame };
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
static BOOL REANodeFind(id<RCTComponent> view, int (^block)(id<RCTComponent>))
|
|
11
|
+
{
|
|
12
|
+
if (!view.reactTag) {
|
|
13
|
+
return NO;
|
|
14
|
+
}
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
if (block(view)) {
|
|
17
|
+
return YES;
|
|
18
|
+
}
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
for (id<RCTComponent> subview in view.reactSubviews) {
|
|
21
|
+
if (REANodeFind(subview, block)) {
|
|
22
|
+
return YES;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return NO;
|
|
27
|
+
}
|
|
20
28
|
|
|
21
29
|
@implementation REAAnimationsManager {
|
|
22
30
|
RCTUIManager *_uiManager;
|
|
23
31
|
REAUIManager *_reaUiManager;
|
|
24
|
-
NSMutableDictionary<NSNumber *,
|
|
25
|
-
NSMutableDictionary<NSNumber *,
|
|
26
|
-
NSMutableSet<NSNumber *> *
|
|
32
|
+
NSMutableDictionary<NSNumber *, UIView *> *_exitingViews;
|
|
33
|
+
NSMutableDictionary<NSNumber *, NSNumber *> *_exitingSubviewsCountMap;
|
|
34
|
+
NSMutableSet<NSNumber *> *_ancestorsToRemove;
|
|
27
35
|
NSMutableArray<NSString *> *_targetKeys;
|
|
28
36
|
NSMutableArray<NSString *> *_currentKeys;
|
|
29
|
-
|
|
37
|
+
REAAnimationStartingBlock _startAnimationForTag;
|
|
38
|
+
REAHasAnimationBlock _hasAnimationForTag;
|
|
39
|
+
REAAnimationRemovingBlock _clearAnimationConfigForTag;
|
|
30
40
|
}
|
|
31
41
|
|
|
32
42
|
+ (NSArray *)layoutKeys
|
|
@@ -44,10 +54,9 @@ typedef NS_ENUM(NSInteger, FrameConfigType) { EnteringFrame, ExitingFrame };
|
|
|
44
54
|
if (self = [super init]) {
|
|
45
55
|
_uiManager = uiManager;
|
|
46
56
|
_reaUiManager = (REAUIManager *)uiManager;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
_cleaningScheduled = false;
|
|
57
|
+
_exitingViews = [NSMutableDictionary new];
|
|
58
|
+
_exitingSubviewsCountMap = [NSMutableDictionary new];
|
|
59
|
+
_ancestorsToRemove = [NSMutableSet new];
|
|
51
60
|
|
|
52
61
|
_targetKeys = [NSMutableArray new];
|
|
53
62
|
_currentKeys = [NSMutableArray new];
|
|
@@ -61,138 +70,77 @@ typedef NS_ENUM(NSInteger, FrameConfigType) { EnteringFrame, ExitingFrame };
|
|
|
61
70
|
|
|
62
71
|
- (void)invalidate
|
|
63
72
|
{
|
|
73
|
+
for (NSNumber *tag in [[_exitingViews allKeys] copy]) {
|
|
74
|
+
[self endLayoutAnimationForTag:tag cancelled:true removeView:true];
|
|
75
|
+
}
|
|
64
76
|
_startAnimationForTag = nil;
|
|
65
|
-
|
|
77
|
+
_hasAnimationForTag = nil;
|
|
66
78
|
_uiManager = nil;
|
|
67
|
-
|
|
68
|
-
_viewForTag = nil;
|
|
69
|
-
_toRemove = nil;
|
|
70
|
-
_cleaningScheduled = false;
|
|
79
|
+
_exitingViews = nil;
|
|
71
80
|
_targetKeys = nil;
|
|
72
81
|
_currentKeys = nil;
|
|
73
82
|
}
|
|
74
83
|
|
|
75
|
-
- (void)setAnimationStartingBlock:
|
|
76
|
-
(void (^)(NSNumber *tag, NSString *type, NSDictionary *yogaValues, NSNumber *depth))startAnimation
|
|
84
|
+
- (void)setAnimationStartingBlock:(REAAnimationStartingBlock)startAnimation
|
|
77
85
|
{
|
|
78
86
|
_startAnimationForTag = startAnimation;
|
|
79
87
|
}
|
|
80
88
|
|
|
81
|
-
- (void)
|
|
89
|
+
- (void)setHasAnimationBlock:(REAHasAnimationBlock)hasAnimation
|
|
82
90
|
{
|
|
83
|
-
|
|
91
|
+
_hasAnimationForTag = hasAnimation;
|
|
84
92
|
}
|
|
85
93
|
|
|
86
|
-
- (void)
|
|
94
|
+
- (void)setAnimationRemovingBlock:(REAAnimationRemovingBlock)clearAnimation
|
|
87
95
|
{
|
|
88
|
-
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
_cleaningScheduled = true;
|
|
92
|
-
|
|
93
|
-
__weak REAAnimationsManager *weakSelf = self;
|
|
94
|
-
dispatch_async(dispatch_get_main_queue(), ^{
|
|
95
|
-
self->_cleaningScheduled = false;
|
|
96
|
-
if (weakSelf == nil) {
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
[self removeLeftovers];
|
|
100
|
-
});
|
|
96
|
+
_clearAnimationConfigForTag = clearAnimation;
|
|
101
97
|
}
|
|
102
98
|
|
|
103
|
-
- (
|
|
99
|
+
- (UIView *)viewForTag:(NSNumber *)tag
|
|
104
100
|
{
|
|
105
|
-
UIView *
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
ViewState state = [_states[currentView.reactTag] intValue];
|
|
109
|
-
if (state == Disappearing) {
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
if (state == ToRemove) {
|
|
113
|
-
lastToRemoveTag = currentView.reactTag;
|
|
114
|
-
}
|
|
115
|
-
currentView = currentView.superview;
|
|
116
|
-
}
|
|
117
|
-
if (lastToRemoveTag != nil) {
|
|
118
|
-
[roots addObject:lastToRemoveTag];
|
|
101
|
+
UIView *view = [_reaUiManager viewForReactTag:tag];
|
|
102
|
+
if (view == nil) {
|
|
103
|
+
return [_exitingViews objectForKey:tag];
|
|
119
104
|
}
|
|
105
|
+
return view;
|
|
120
106
|
}
|
|
121
107
|
|
|
122
|
-
- (
|
|
108
|
+
- (void)endLayoutAnimationForTag:(NSNumber *)tag cancelled:(BOOL)cancelled removeView:(BOOL)removeView
|
|
123
109
|
{
|
|
124
|
-
|
|
125
|
-
if (
|
|
126
|
-
|
|
110
|
+
UIView *view = [_exitingViews objectForKey:tag];
|
|
111
|
+
if (removeView && view != nil) {
|
|
112
|
+
[self endAnimationsRecursive:view];
|
|
113
|
+
[view removeFromSuperview];
|
|
127
114
|
}
|
|
128
|
-
if (![cands containsObject:tag] && _states[tag] != nil) {
|
|
129
|
-
return true;
|
|
130
|
-
}
|
|
131
|
-
BOOL cannotStripe = false;
|
|
132
|
-
NSArray<UIView *> *toRemoveCopy = [view.reactSubviews copy];
|
|
133
|
-
for (UIView *child in toRemoveCopy) {
|
|
134
|
-
if (![view isKindOfClass:[RCTTextView class]]) {
|
|
135
|
-
cannotStripe |= [self dfs:root view:child cands:cands];
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
if (!cannotStripe) {
|
|
139
|
-
if (view.reactSuperview != nil) {
|
|
140
|
-
[_reaUiManager unregisterView:view];
|
|
141
|
-
}
|
|
142
|
-
[_states removeObjectForKey:tag];
|
|
143
|
-
[_viewForTag removeObjectForKey:tag];
|
|
144
|
-
[_toRemove removeObject:tag];
|
|
145
|
-
}
|
|
146
|
-
return cannotStripe;
|
|
147
115
|
}
|
|
148
116
|
|
|
149
|
-
- (void)
|
|
117
|
+
- (void)endAnimationsRecursive:(UIView *)view
|
|
150
118
|
{
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
view = [_reaUiManager viewForReactTag:viewTag];
|
|
156
|
-
_viewForTag[viewTag] = view;
|
|
157
|
-
}
|
|
158
|
-
[self findRoot:view roots:roots];
|
|
119
|
+
NSNumber *tag = [view reactTag];
|
|
120
|
+
|
|
121
|
+
if (tag == nil) {
|
|
122
|
+
return;
|
|
159
123
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
124
|
+
|
|
125
|
+
// we'll remove this view anyway when exiting from recursion,
|
|
126
|
+
// no need to remove it in `maybeDropAncestors`
|
|
127
|
+
[_ancestorsToRemove removeObject:tag];
|
|
128
|
+
|
|
129
|
+
for (UIView *child in [[view subviews] copy]) {
|
|
130
|
+
[self endAnimationsRecursive:child];
|
|
163
131
|
}
|
|
164
|
-
}
|
|
165
132
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
ViewState state = [_states[tag] intValue];
|
|
170
|
-
if (state == Appearing) {
|
|
171
|
-
_states[tag] = [NSNumber numberWithInt:Layout];
|
|
172
|
-
}
|
|
173
|
-
if (state == Disappearing) {
|
|
174
|
-
_states[tag] = [NSNumber numberWithInt:ToRemove];
|
|
175
|
-
if (tag != nil) {
|
|
176
|
-
[_toRemove addObject:tag];
|
|
177
|
-
}
|
|
178
|
-
[self scheduleCleaning];
|
|
179
|
-
}
|
|
133
|
+
if ([_exitingViews objectForKey:tag]) {
|
|
134
|
+
[_exitingViews removeObjectForKey:tag];
|
|
135
|
+
[self maybeDropAncestors:view];
|
|
180
136
|
}
|
|
181
137
|
}
|
|
182
138
|
|
|
183
|
-
- (void)
|
|
139
|
+
- (void)progressLayoutAnimationWithStyle:(NSDictionary *)newStyle forTag:(NSNumber *)tag
|
|
184
140
|
{
|
|
185
|
-
if (_states[tag] == nil) {
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
ViewState state = [_states[tag] intValue];
|
|
189
|
-
if (state == Inactive) {
|
|
190
|
-
_states[tag] = [NSNumber numberWithInt:Appearing];
|
|
191
|
-
}
|
|
192
|
-
|
|
193
141
|
NSMutableDictionary *dataComponenetsByName = [_uiManager valueForKey:@"_componentDataByName"];
|
|
194
142
|
RCTComponentData *componentData = dataComponenetsByName[@"RCTView"];
|
|
195
|
-
[self setNewProps:[newStyle mutableCopy] forView:
|
|
143
|
+
[self setNewProps:[newStyle mutableCopy] forView:[self viewForTag:tag] withComponentData:componentData];
|
|
196
144
|
}
|
|
197
145
|
|
|
198
146
|
- (double)getDoubleOrZero:(NSNumber *)number
|
|
@@ -288,73 +236,160 @@ typedef NS_ENUM(NSInteger, FrameConfigType) { EnteringFrame, ExitingFrame };
|
|
|
288
236
|
return preparedData;
|
|
289
237
|
}
|
|
290
238
|
|
|
291
|
-
- (
|
|
239
|
+
- (BOOL)wantsHandleRemovalOfView:(UIView *)view
|
|
292
240
|
{
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
241
|
+
return REANodeFind(view, ^(id<RCTComponent> view) {
|
|
242
|
+
return [self->_exitingSubviewsCountMap objectForKey:view.reactTag] != nil ||
|
|
243
|
+
self->_hasAnimationForTag(view.reactTag, @"exiting");
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
- (void)registerExitingAncestors:(UIView *)child
|
|
248
|
+
{
|
|
249
|
+
UIView *parent = child.superview;
|
|
250
|
+
while (parent != nil && ![parent isKindOfClass:[RCTRootView class]]) {
|
|
251
|
+
if (parent.reactTag != nil) {
|
|
252
|
+
_exitingSubviewsCountMap[parent.reactTag] = @([_exitingSubviewsCountMap[parent.reactTag] intValue] + 1);
|
|
253
|
+
}
|
|
254
|
+
parent = parent.superview;
|
|
297
255
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
- (void)maybeDropAncestors:(UIView *)child
|
|
259
|
+
{
|
|
260
|
+
UIView *parent = child.superview;
|
|
261
|
+
while (parent != nil && ![parent isKindOfClass:[RCTRootView class]]) {
|
|
262
|
+
UIView *view = parent;
|
|
263
|
+
parent = view.superview;
|
|
264
|
+
if (view.reactTag == nil) {
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
int trackingCount = [_exitingSubviewsCountMap[view.reactTag] intValue] - 1;
|
|
268
|
+
if (trackingCount <= 0) {
|
|
269
|
+
if ([_ancestorsToRemove containsObject:view.reactTag]) {
|
|
270
|
+
[_ancestorsToRemove removeObject:view.reactTag];
|
|
271
|
+
if (![_exitingViews objectForKey:view.reactTag]) {
|
|
272
|
+
[view removeFromSuperview];
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
[_exitingSubviewsCountMap removeObjectForKey:view.reactTag];
|
|
276
|
+
} else {
|
|
277
|
+
_exitingSubviewsCountMap[view.reactTag] = @(trackingCount);
|
|
304
278
|
}
|
|
305
|
-
return;
|
|
306
279
|
}
|
|
307
|
-
_states[tag] = [NSNumber numberWithInt:Disappearing];
|
|
308
|
-
NSDictionary *preparedValues = [self prepareDataForAnimatingWorklet:startValues frameConfig:ExitingFrame];
|
|
309
|
-
_startAnimationForTag(tag, @"exiting", preparedValues, @(0));
|
|
310
280
|
}
|
|
311
281
|
|
|
312
|
-
- (
|
|
282
|
+
- (BOOL)removeRecursive:(UIView *)view fromContainer:(UIView *)container withoutAnimation:(BOOL)removeImmediately;
|
|
313
283
|
{
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
if (_states[tag] == nil) {
|
|
317
|
-
_states[tag] = [NSNumber numberWithInt:Inactive];
|
|
318
|
-
_viewForTag[tag] = view;
|
|
284
|
+
if (!view.reactTag) {
|
|
285
|
+
return NO;
|
|
319
286
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
287
|
+
BOOL hasExitAnimation = _hasAnimationForTag(view.reactTag, @"exiting") || [_exitingViews objectForKey:view.reactTag];
|
|
288
|
+
BOOL hasAnimatedChildren = NO;
|
|
289
|
+
removeImmediately = removeImmediately && !hasExitAnimation;
|
|
290
|
+
NSMutableArray *toBeRemoved = [[NSMutableArray alloc] init];
|
|
291
|
+
|
|
292
|
+
for (UIView *subview in [view.reactSubviews copy]) {
|
|
293
|
+
if ([self removeRecursive:subview fromContainer:view withoutAnimation:removeImmediately]) {
|
|
294
|
+
hasAnimatedChildren = YES;
|
|
295
|
+
} else if (removeImmediately) {
|
|
296
|
+
[toBeRemoved addObject:subview];
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
BOOL wantAnimateExit = hasExitAnimation || hasAnimatedChildren;
|
|
301
|
+
|
|
302
|
+
if (!wantAnimateExit) {
|
|
303
|
+
return NO;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
REASnapshot *before;
|
|
307
|
+
if (hasExitAnimation) {
|
|
308
|
+
before = [[REASnapshot alloc] init:view];
|
|
309
|
+
}
|
|
310
|
+
// start exit animation
|
|
311
|
+
UIView *originalSuperview = view.superview;
|
|
312
|
+
NSUInteger originalIndex = [originalSuperview.subviews indexOfObjectIdenticalTo:view];
|
|
313
|
+
[container removeReactSubview:view];
|
|
314
|
+
// we don't want user interaction on exiting views
|
|
315
|
+
view.userInteractionEnabled = NO;
|
|
316
|
+
[originalSuperview insertSubview:view atIndex:originalIndex];
|
|
317
|
+
|
|
318
|
+
if (hasExitAnimation && ![_exitingViews objectForKey:view.reactTag]) {
|
|
319
|
+
NSDictionary *preparedValues = [self prepareDataForAnimatingWorklet:before.values frameConfig:ExitingFrame];
|
|
320
|
+
[_exitingViews setObject:view forKey:view.reactTag];
|
|
321
|
+
[self registerExitingAncestors:view];
|
|
322
|
+
_startAnimationForTag(view.reactTag, @"exiting", preparedValues, @(0));
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (hasAnimatedChildren) {
|
|
326
|
+
[_ancestorsToRemove addObject:view.reactTag];
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
for (UIView *child in toBeRemoved) {
|
|
330
|
+
[view removeReactSubview:child];
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// NOTE: even though this view is still visible,
|
|
334
|
+
// since it's removed from the React tree, we won't
|
|
335
|
+
// start new animations for it, and might as well remove
|
|
336
|
+
// the layout animation config now
|
|
337
|
+
_clearAnimationConfigForTag(view.reactTag);
|
|
338
|
+
return YES;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
- (void)removeChildren:(NSArray<UIView *> *)children fromContainer:(UIView *)container
|
|
342
|
+
{
|
|
343
|
+
for (UIView *removedChild in children) {
|
|
344
|
+
if (![self removeRecursive:removedChild fromContainer:container withoutAnimation:true]) {
|
|
345
|
+
[removedChild removeFromSuperview];
|
|
326
346
|
}
|
|
327
|
-
return;
|
|
328
347
|
}
|
|
329
348
|
}
|
|
330
349
|
|
|
350
|
+
- (void)onViewCreate:(UIView *)view after:(REASnapshot *)after
|
|
351
|
+
{
|
|
352
|
+
NSMutableDictionary *targetValues = after.values;
|
|
353
|
+
NSDictionary *preparedValues = [self prepareDataForAnimatingWorklet:targetValues frameConfig:EnteringFrame];
|
|
354
|
+
_startAnimationForTag(view.reactTag, @"entering", preparedValues, @(0));
|
|
355
|
+
}
|
|
356
|
+
|
|
331
357
|
- (void)onViewUpdate:(UIView *)view before:(REASnapshot *)before after:(REASnapshot *)after
|
|
332
358
|
{
|
|
333
|
-
NSNumber *tag = view.reactTag;
|
|
334
359
|
NSMutableDictionary *targetValues = after.values;
|
|
335
360
|
NSMutableDictionary *currentValues = before.values;
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
361
|
+
|
|
362
|
+
NSDictionary *preparedValues = [self prepareDataForLayoutAnimatingWorklet:currentValues targetValues:targetValues];
|
|
363
|
+
_startAnimationForTag(view.reactTag, @"layout", preparedValues, @(0));
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
- (REASnapshot *)prepareSnapshotBeforeMountForView:(UIView *)view
|
|
367
|
+
{
|
|
368
|
+
if (_hasAnimationForTag(view.reactTag, @"layout")) {
|
|
369
|
+
return [[REASnapshot alloc] init:view];
|
|
342
370
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
if (
|
|
352
|
-
|
|
371
|
+
return nil;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
- (void)viewDidMount:(UIView *)view withBeforeSnapshot:(nonnull REASnapshot *)before
|
|
375
|
+
{
|
|
376
|
+
NSString *type = before == nil ? @"entering" : @"layout";
|
|
377
|
+
if (_hasAnimationForTag(view.reactTag, type)) {
|
|
378
|
+
REASnapshot *after = [[REASnapshot alloc] init:view];
|
|
379
|
+
if (before == nil) {
|
|
380
|
+
[self onViewCreate:view after:after];
|
|
381
|
+
} else {
|
|
382
|
+
[self onViewUpdate:view before:before after:after];
|
|
353
383
|
}
|
|
354
384
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
- (void)removeAnimationsFromSubtree:(UIView *)view
|
|
388
|
+
{
|
|
389
|
+
REANodeFind(view, ^int(id<RCTComponent> view) {
|
|
390
|
+
self->_clearAnimationConfigForTag(view.reactTag);
|
|
391
|
+
return false;
|
|
392
|
+
});
|
|
358
393
|
}
|
|
359
394
|
|
|
360
395
|
@end
|
|
@@ -24,17 +24,25 @@
|
|
|
24
24
|
removeAtIndices:(NSArray<NSNumber *> *)removeAtIndices
|
|
25
25
|
registry:(NSMutableDictionary<NSNumber *, id<RCTComponent>> *)registry;
|
|
26
26
|
|
|
27
|
+
- (void)_removeChildren:(NSArray<UIView *> *)children fromContainer:(UIView *)container;
|
|
28
|
+
|
|
29
|
+
- (void)_removeChildren:(NSArray<UIView *> *)children
|
|
30
|
+
fromContainer:(UIView *)container
|
|
31
|
+
withAnimation:(RCTLayoutAnimationGroup *)animation;
|
|
32
|
+
|
|
33
|
+
- (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView *)rootShadowView;
|
|
34
|
+
|
|
27
35
|
- (NSArray<id<RCTComponent>> *)_childrenToRemoveFromContainer:(id<RCTComponent>)container
|
|
28
36
|
atIndices:(NSArray<NSNumber *> *)atIndices;
|
|
29
37
|
@end
|
|
30
38
|
|
|
31
|
-
@implementation REAUIManager
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
NSMutableDictionary<NSNumber *,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
@implementation REAUIManager {
|
|
40
|
+
RCTLayoutAnimationGroup *_reactLayoutAnimationGroup;
|
|
41
|
+
NSMutableDictionary<NSNumber *, NSMutableSet<id<RCTComponent>> *> *_toBeRemovedRegister;
|
|
42
|
+
NSMutableDictionary<NSNumber *, NSNumber *> *_parentMapper;
|
|
43
|
+
REAAnimationsManager *_animationsManager;
|
|
44
|
+
std::weak_ptr<reanimated::Scheduler> _scheduler;
|
|
45
|
+
}
|
|
38
46
|
|
|
39
47
|
+ (NSString *)moduleName
|
|
40
48
|
{
|
|
@@ -43,6 +51,13 @@ std::weak_ptr<reanimated::Scheduler> _scheduler;
|
|
|
43
51
|
|
|
44
52
|
- (void)setBridge:(RCTBridge *)bridge
|
|
45
53
|
{
|
|
54
|
+
// setting a layout animation group with a deleting animation in order to
|
|
55
|
+
// allows us to call a different method in RCTUIManager for cleaning up exiting views
|
|
56
|
+
RCTLayoutAnimation *deletingAnimation = [[RCTLayoutAnimation alloc] initWithDuration:0 config:@{}];
|
|
57
|
+
_reactLayoutAnimationGroup = [[RCTLayoutAnimationGroup alloc] initWithCreatingLayoutAnimation:nil
|
|
58
|
+
updatingLayoutAnimation:nil
|
|
59
|
+
deletingLayoutAnimation:deletingAnimation
|
|
60
|
+
callback:nil];
|
|
46
61
|
if (!_blockSetter) {
|
|
47
62
|
_blockSetter = true;
|
|
48
63
|
|
|
@@ -64,6 +79,21 @@ std::weak_ptr<reanimated::Scheduler> _scheduler;
|
|
|
64
79
|
}
|
|
65
80
|
}
|
|
66
81
|
|
|
82
|
+
- (void)_removeChildren:(NSArray<UIView *> *)children
|
|
83
|
+
fromContainer:(UIView *)container
|
|
84
|
+
withAnimation:(RCTLayoutAnimationGroup *)animation
|
|
85
|
+
{
|
|
86
|
+
if (animation == _reactLayoutAnimationGroup) {
|
|
87
|
+
// if a removed view in this batch has an `exiting` animation,
|
|
88
|
+
// let REAAnimationsManager handle the removal
|
|
89
|
+
[_animationsManager removeChildren:children fromContainer:container];
|
|
90
|
+
} else {
|
|
91
|
+
// otherwise, if there's a layout animation group set,
|
|
92
|
+
// delegate to the React Native implementation for layout animations
|
|
93
|
+
[super _removeChildren:children fromContainer:container withAnimation:animation];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
67
97
|
- (void)_manageChildren:(NSNumber *)containerTag
|
|
68
98
|
moveFromIndices:(NSArray<NSNumber *> *)moveFromIndices
|
|
69
99
|
moveToIndices:(NSArray<NSNumber *> *)moveToIndices
|
|
@@ -85,22 +115,23 @@ std::weak_ptr<reanimated::Scheduler> _scheduler;
|
|
|
85
115
|
|
|
86
116
|
// Reanimated changes /start
|
|
87
117
|
BOOL isUIViewRegistry = ((id)registry == (id)[self valueForKey:@"_viewRegistry"]);
|
|
88
|
-
id<RCTComponent> container;
|
|
89
|
-
NSMutableArray<id<RCTComponent>> *permanentlyRemovedChildren;
|
|
90
118
|
if (isUIViewRegistry) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
_toBeRemovedRegister[containerTag] = [[NSMutableSet<id<RCTComponent>> alloc] init];
|
|
119
|
+
BOOL wasProxyRemovalSet = [self valueForKey:@"_layoutAnimationGroup"] == _reactLayoutAnimationGroup;
|
|
120
|
+
BOOL wantProxyRemoval = NO;
|
|
121
|
+
if (!wasProxyRemovalSet) {
|
|
122
|
+
id<RCTComponent> container = registry[containerTag];
|
|
123
|
+
NSArray<id<RCTComponent>> *permanentlyRemovedChildren = [self _childrenToRemoveFromContainer:container
|
|
124
|
+
atIndices:removeAtIndices];
|
|
125
|
+
for (UIView *removedChild in permanentlyRemovedChildren) {
|
|
126
|
+
if ([_animationsManager wantsHandleRemovalOfView:removedChild]) {
|
|
127
|
+
wantProxyRemoval = YES;
|
|
128
|
+
break;
|
|
102
129
|
}
|
|
103
|
-
[
|
|
130
|
+
[_animationsManager removeAnimationsFromSubtree:removedChild];
|
|
131
|
+
}
|
|
132
|
+
if (wantProxyRemoval) {
|
|
133
|
+
// set layout animation group
|
|
134
|
+
[super setNextLayoutAnimationGroup:_reactLayoutAnimationGroup];
|
|
104
135
|
}
|
|
105
136
|
}
|
|
106
137
|
}
|
|
@@ -113,43 +144,11 @@ std::weak_ptr<reanimated::Scheduler> _scheduler;
|
|
|
113
144
|
addAtIndices:addAtIndices
|
|
114
145
|
removeAtIndices:removeAtIndices
|
|
115
146
|
registry:registry];
|
|
116
|
-
|
|
117
|
-
// Reanimated changes /start
|
|
118
|
-
if (isUIViewRegistry) {
|
|
119
|
-
NSMutableDictionary<NSNumber *, id<RCTComponent>> *viewRegistry = [self valueForKey:@"_viewRegistry"];
|
|
120
|
-
for (id<RCTComponent> toRemoveChild in _toBeRemovedRegister[containerTag]) {
|
|
121
|
-
NSInteger lastIndex = [container reactSubviews].count - 1;
|
|
122
|
-
if (lastIndex < 0) {
|
|
123
|
-
lastIndex = 0;
|
|
124
|
-
}
|
|
125
|
-
if ([toRemoveChild isKindOfClass:[RCTModalHostView class]]
|
|
126
|
-
#if __has_include(<RNScreens/RNSScreen.h>)
|
|
127
|
-
|| ([toRemoveChild isKindOfClass:[RNSScreenView class]])
|
|
128
|
-
#endif
|
|
129
|
-
) {
|
|
130
|
-
// we don't want layout animations when removing modals or Screens of native-stack since it brings buggy
|
|
131
|
-
// behavior
|
|
132
|
-
[_toBeRemovedRegister[container.reactTag] removeObject:toRemoveChild];
|
|
133
|
-
[permanentlyRemovedChildren removeObject:toRemoveChild];
|
|
134
|
-
|
|
135
|
-
} else {
|
|
136
|
-
[container insertReactSubview:toRemoveChild atIndex:lastIndex];
|
|
137
|
-
viewRegistry[toRemoveChild.reactTag] = toRemoveChild;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
for (UIView *removedChild in permanentlyRemovedChildren) {
|
|
142
|
-
[self callAnimationForTree:removedChild parentTag:containerTag];
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
// Reanimated changes /end
|
|
146
147
|
}
|
|
147
148
|
|
|
148
149
|
- (void)callAnimationForTree:(UIView *)view parentTag:(NSNumber *)parentTag
|
|
149
150
|
{
|
|
150
|
-
REASnapshot *snapshot = [[REASnapshot alloc] init:view];
|
|
151
151
|
_parentMapper[view.reactTag] = parentTag;
|
|
152
|
-
[_animationsManager onViewRemoval:view before:snapshot];
|
|
153
152
|
|
|
154
153
|
for (UIView *subView in view.reactSubviews) {
|
|
155
154
|
[self callAnimationForTree:subView parentTag:view.reactTag];
|
|
@@ -159,6 +158,10 @@ std::weak_ptr<reanimated::Scheduler> _scheduler;
|
|
|
159
158
|
// Overrided https://github.com/facebook/react-native/blob/v0.65.0/React/Modules/RCTUIManager.m#L530
|
|
160
159
|
- (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView *)rootShadowView
|
|
161
160
|
{
|
|
161
|
+
if (!reanimated::FeaturesConfig::isLayoutAnimationEnabled()) {
|
|
162
|
+
return [super uiBlockWithLayoutUpdateForRootView:rootShadowView];
|
|
163
|
+
}
|
|
164
|
+
|
|
162
165
|
NSHashTable<RCTShadowView *> *affectedShadowViews = [NSHashTable weakObjectsHashTable];
|
|
163
166
|
[rootShadowView layoutWithAffectedShadowViews:affectedShadowViews];
|
|
164
167
|
|
|
@@ -270,10 +273,7 @@ std::weak_ptr<reanimated::Scheduler> _scheduler;
|
|
|
270
273
|
}
|
|
271
274
|
|
|
272
275
|
// Reanimated changes /start
|
|
273
|
-
REASnapshot *snapshotBefore;
|
|
274
|
-
if (reanimated::FeaturesConfig::isLayoutAnimationEnabled()) {
|
|
275
|
-
snapshotBefore = [[REASnapshot alloc] init:view];
|
|
276
|
-
}
|
|
276
|
+
REASnapshot *snapshotBefore = isNew ? nil : [self->_animationsManager prepareSnapshotBeforeMountForView:view];
|
|
277
277
|
// Reanimated changes /end
|
|
278
278
|
|
|
279
279
|
if (creatingLayoutAnimation) {
|
|
@@ -322,22 +322,15 @@ std::weak_ptr<reanimated::Scheduler> _scheduler;
|
|
|
322
322
|
}
|
|
323
323
|
|
|
324
324
|
// Reanimated changes /start
|
|
325
|
-
if (
|
|
326
|
-
|
|
327
|
-
REASnapshot *snapshot = [[REASnapshot alloc] init:view];
|
|
328
|
-
[_animationsManager onViewCreate:view after:snapshot];
|
|
329
|
-
} else {
|
|
330
|
-
REASnapshot *snapshotAfter = [[REASnapshot alloc] init:view];
|
|
331
|
-
[_animationsManager onViewUpdate:view before:snapshotBefore after:snapshotAfter];
|
|
332
|
-
}
|
|
325
|
+
if (isNew || snapshotBefore != nil) {
|
|
326
|
+
[self->_animationsManager viewDidMount:view withBeforeSnapshot:snapshotBefore];
|
|
333
327
|
}
|
|
328
|
+
// Reanimated changes /end
|
|
334
329
|
}
|
|
335
|
-
|
|
336
|
-
[_animationsManager removeLeftovers];
|
|
337
330
|
// Clean up
|
|
338
|
-
// uiManager->_layoutAnimationGroup = nil
|
|
339
|
-
|
|
340
|
-
|
|
331
|
+
// below line serves as this one uiManager->_layoutAnimationGroup = nil;, because we don't have access to the
|
|
332
|
+
// private field
|
|
333
|
+
[uiManager setNextLayoutAnimationGroup:nil];
|
|
341
334
|
};
|
|
342
335
|
}
|
|
343
336
|
|