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.
Files changed (61) hide show
  1. package/Common/cpp/LayoutAnimations/LayoutAnimationsProxy.cpp +97 -15
  2. package/Common/cpp/LayoutAnimations/LayoutAnimationsProxy.h +32 -8
  3. package/Common/cpp/NativeModules/NativeReanimatedModule.cpp +16 -1
  4. package/Common/cpp/NativeModules/NativeReanimatedModule.h +8 -1
  5. package/Common/cpp/NativeModules/NativeReanimatedModuleSpec.cpp +17 -0
  6. package/Common/cpp/NativeModules/NativeReanimatedModuleSpec.h +8 -0
  7. package/Common/cpp/ReanimatedRuntime/ReanimatedRuntime.cpp +2 -1
  8. package/Common/cpp/ReanimatedRuntime/ReanimatedRuntime.h +1 -0
  9. package/Common/cpp/Tools/RuntimeDecorator.cpp +2 -1
  10. package/android/CMakeLists.txt +1 -0
  11. package/android/build.gradle +9 -1
  12. package/android/src/fabric/java/com/swmansion/reanimated/NativeProxy.java +16 -25
  13. package/android/src/main/cpp/LayoutAnimations.cpp +42 -50
  14. package/android/src/main/cpp/LayoutAnimations.h +17 -3
  15. package/android/src/main/cpp/NativeProxy.cpp +55 -6
  16. package/android/src/main/java/com/swmansion/reanimated/NodesManager.java +1 -1
  17. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/AnimationsManager.java +208 -223
  18. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/LayoutAnimations.java +7 -5
  19. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/NativeMethodsHolder.java +5 -3
  20. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/ViewHierarchyObserver.java +1 -1
  21. package/android/src/paper/java/com/swmansion/reanimated/NativeProxy.java +20 -7
  22. package/android/src/reactNativeVersionPatch/nativeHierarchyManager/62/com/swmansion/reanimated/layoutReanimation/ReanimatedNativeHierarchyManager.java +8 -44
  23. package/android/src/reactNativeVersionPatch/nativeHierarchyManager/latest/com/swmansion/reanimated/layoutReanimation/ReanimatedNativeHierarchyManager.java +15 -61
  24. package/ios/LayoutReanimation/REAAnimationsManager.h +18 -8
  25. package/ios/LayoutReanimation/REAAnimationsManager.m +197 -162
  26. package/ios/LayoutReanimation/REAUIManager.mm +63 -70
  27. package/ios/native/NativeProxy.mm +55 -48
  28. package/lib/commonjs/createAnimatedComponent.js +26 -26
  29. package/lib/commonjs/createAnimatedComponent.js.map +1 -1
  30. package/lib/commonjs/reanimated2/NativeReanimated/NativeReanimated.js +4 -0
  31. package/lib/commonjs/reanimated2/NativeReanimated/NativeReanimated.js.map +1 -1
  32. package/lib/commonjs/reanimated2/core.js +9 -9
  33. package/lib/commonjs/reanimated2/core.js.map +1 -1
  34. package/lib/commonjs/reanimated2/globals.d.js.map +1 -1
  35. package/lib/commonjs/reanimated2/jestUtils.js +17 -9
  36. package/lib/commonjs/reanimated2/jestUtils.js.map +1 -1
  37. package/lib/commonjs/reanimated2/layoutReanimation/LayoutAnimationRepository.js +23 -62
  38. package/lib/commonjs/reanimated2/layoutReanimation/LayoutAnimationRepository.js.map +1 -1
  39. package/lib/module/createAnimatedComponent.js +27 -26
  40. package/lib/module/createAnimatedComponent.js.map +1 -1
  41. package/lib/module/reanimated2/NativeReanimated/NativeReanimated.js +4 -0
  42. package/lib/module/reanimated2/NativeReanimated/NativeReanimated.js.map +1 -1
  43. package/lib/module/reanimated2/core.js +7 -9
  44. package/lib/module/reanimated2/core.js.map +1 -1
  45. package/lib/module/reanimated2/globals.d.js.map +1 -1
  46. package/lib/module/reanimated2/jestUtils.js +17 -9
  47. package/lib/module/reanimated2/jestUtils.js.map +1 -1
  48. package/lib/module/reanimated2/layoutReanimation/LayoutAnimationRepository.js +22 -61
  49. package/lib/module/reanimated2/layoutReanimation/LayoutAnimationRepository.js.map +1 -1
  50. package/package.json +2 -2
  51. package/src/createAnimatedComponent.tsx +48 -39
  52. package/src/reanimated2/NativeReanimated/NativeReanimated.ts +15 -0
  53. package/src/reanimated2/core.ts +19 -10
  54. package/src/reanimated2/globals.d.ts +10 -6
  55. package/src/reanimated2/jestUtils.ts +14 -6
  56. package/src/reanimated2/layoutReanimation/LayoutAnimationRepository.ts +24 -50
  57. package/lib/commonjs/reanimated2/layoutReanimation/defaultAnimations/Default.js +0 -55
  58. package/lib/commonjs/reanimated2/layoutReanimation/defaultAnimations/Default.js.map +0 -1
  59. package/lib/module/reanimated2/layoutReanimation/defaultAnimations/Default.js +0 -40
  60. package/lib/module/reanimated2/layoutReanimation/defaultAnimations/Default.js.map +0 -1
  61. package/src/reanimated2/layoutReanimation/defaultAnimations/Default.ts +0 -49
@@ -203,7 +203,7 @@ void NativeProxy::installJSIBindings(
203
203
 
204
204
  auto jsQueue = std::make_shared<JMessageQueueThread>(messageQueueThread);
205
205
  std::shared_ptr<jsi::Runtime> animatedRuntime =
206
- ReanimatedRuntime::make(jsQueue);
206
+ ReanimatedRuntime::make(runtime_, jsQueue);
207
207
 
208
208
  auto workletRuntimeValue =
209
209
  runtime_->global()
@@ -230,19 +230,68 @@ void NativeProxy::installJSIBindings(
230
230
 
231
231
  // Layout Animations Start
232
232
 
233
- auto notifyAboutProgress = [=](int tag, jsi::Value progress) {
234
- this->layoutAnimations->cthis()->notifyAboutProgress(progress, tag);
233
+ auto progressLayoutAnimation = [this](int tag, jsi::Value progress) {
234
+ this->layoutAnimations->cthis()->progressLayoutAnimation(tag, progress);
235
235
  };
236
236
 
237
- auto notifyAboutEnd = [=](int tag, bool isCancelled) {
238
- this->layoutAnimations->cthis()->notifyAboutEnd(tag, (isCancelled) ? 1 : 0);
237
+ auto endLayoutAnimation = [this](int tag, bool isCancelled, bool removeView) {
238
+ this->layoutAnimations->cthis()->endLayoutAnimation(
239
+ tag, isCancelled, removeView);
239
240
  };
240
241
 
241
242
  std::shared_ptr<LayoutAnimationsProxy> layoutAnimationsProxy =
242
243
  std::make_shared<LayoutAnimationsProxy>(
243
- notifyAboutProgress, notifyAboutEnd);
244
+ progressLayoutAnimation, endLayoutAnimation, errorHandler);
244
245
  std::weak_ptr<jsi::Runtime> wrt = animatedRuntime;
246
+ std::weak_ptr<LayoutAnimationsProxy> weakLayoutAnimationsProxy =
247
+ layoutAnimationsProxy;
245
248
  layoutAnimations->cthis()->setWeakUIRuntime(wrt);
249
+ std::weak_ptr<ErrorHandler> weakErrorHandler = errorHandler;
250
+
251
+ layoutAnimations->cthis()->setAnimationStartingBlock(
252
+ [wrt, weakLayoutAnimationsProxy, weakErrorHandler](
253
+ int tag,
254
+ alias_ref<JString> type,
255
+ alias_ref<JMap<jstring, jstring>> values) {
256
+ auto runtime = wrt.lock();
257
+ auto layoutAnimationsProxy = weakLayoutAnimationsProxy.lock();
258
+ if (!runtime || !layoutAnimationsProxy) {
259
+ return;
260
+ }
261
+ auto &rt = *runtime;
262
+ jsi::Object yogaValues(rt);
263
+ for (const auto &entry : *values) {
264
+ try {
265
+ auto key =
266
+ jsi::String::createFromAscii(rt, entry.first->toStdString());
267
+ auto value = stod(entry.second->toStdString());
268
+ yogaValues.setProperty(rt, key, value);
269
+ } catch (std::invalid_argument e) {
270
+ if (auto errorHandler = weakErrorHandler.lock()) {
271
+ errorHandler->setError("Failed to convert value to number");
272
+ errorHandler->raise();
273
+ }
274
+ }
275
+ }
276
+
277
+ layoutAnimationsProxy->startLayoutAnimation(
278
+ *runtime, tag, type->toStdString(), yogaValues);
279
+ });
280
+
281
+ layoutAnimations->cthis()->setHasAnimationBlock(
282
+ [weakLayoutAnimationsProxy](int tag, std::string type) {
283
+ auto layoutAnimationsProxy = weakLayoutAnimationsProxy.lock();
284
+ return layoutAnimationsProxy &&
285
+ layoutAnimationsProxy->hasLayoutAnimation(tag, type);
286
+ });
287
+
288
+ layoutAnimations->cthis()->setClearAnimationConfigBlock(
289
+ [weakLayoutAnimationsProxy](int tag) {
290
+ auto layoutAnimationsProxy = weakLayoutAnimationsProxy.lock();
291
+ if (layoutAnimationsProxy) {
292
+ layoutAnimationsProxy->clearLayoutAnimationConfig(tag);
293
+ }
294
+ });
246
295
 
247
296
  // Layout Animations End
248
297
 
@@ -153,7 +153,7 @@ public class NodesManager implements EventDispatcherListener {
153
153
  // registration, creating race condition
154
154
  mUIManager.getEventDispatcher().addListener(this);
155
155
 
156
- mAnimationManager = new AnimationsManager(mContext, mUIImplementation, mUIManager);
156
+ mAnimationManager = new AnimationsManager(mContext, mUIManager);
157
157
  }
158
158
 
159
159
  public void onHostPause() {
@@ -16,9 +16,7 @@ import com.facebook.react.uimanager.IllegalViewOperationException;
16
16
  import com.facebook.react.uimanager.PixelUtil;
17
17
  import com.facebook.react.uimanager.ReactStylesDiffMap;
18
18
  import com.facebook.react.uimanager.RootView;
19
- import com.facebook.react.uimanager.UIImplementation;
20
19
  import com.facebook.react.uimanager.UIManagerModule;
21
- import com.facebook.react.uimanager.ViewGroupManager;
22
20
  import com.facebook.react.uimanager.ViewManager;
23
21
  import com.swmansion.reanimated.Scheduler;
24
22
  import java.lang.ref.WeakReference;
@@ -28,25 +26,17 @@ import java.util.HashSet;
28
26
  import java.util.Map;
29
27
 
30
28
  public class AnimationsManager implements ViewHierarchyObserver {
31
- private static final String[] LAYOUT_KEYS = {
32
- Snapshot.ORIGIN_X, Snapshot.ORIGIN_Y, Snapshot.WIDTH, Snapshot.HEIGHT
33
- };
34
29
  private WeakReference<Scheduler> mScheduler;
35
30
  private ReactContext mContext;
36
- private UIImplementation mUIImplementation;
37
31
  private UIManagerModule mUIManager;
38
32
  private NativeMethodsHolder mNativeMethodsHolder;
39
33
 
40
- private HashMap<Integer, ViewState> mStates;
41
- private HashMap<Integer, View> mViewForTag;
42
- private HashSet<Integer> mToRemove;
43
- private HashMap<Integer, ViewManager> mViewManager;
44
- private HashMap<Integer, ViewManager> mParentViewManager;
45
- private HashMap<Integer, View> mParent;
46
- private HashMap<Integer, Runnable> mCallbacks;
47
- private boolean mCleaningScheduled = false;
34
+ private HashMap<Integer, View> mExitingViews = new HashMap<>();
35
+ private HashMap<Integer, Integer> mExitingSubviewCountMap = new HashMap<>();
36
+ private HashSet<Integer> mAncestorsToRemove = new HashSet<>();
37
+ private HashMap<Integer, Runnable> mCallbacks = new HashMap<>();
48
38
  private ReanimatedNativeHierarchyManager mReanimatedNativeHierarchyManager;
49
- private boolean isCatalystInstanceDestroyed = false;
39
+ private boolean isCatalystInstanceDestroyed;
50
40
 
51
41
  public void setReanimatedNativeHierarchyManager(
52
42
  ReanimatedNativeHierarchyManager reanimatedNativeHierarchyManager) {
@@ -61,26 +51,9 @@ public class AnimationsManager implements ViewHierarchyObserver {
61
51
  mScheduler = new WeakReference<>(scheduler);
62
52
  }
63
53
 
64
- public enum ViewState {
65
- Inactive,
66
- Appearing,
67
- Disappearing,
68
- Layout,
69
- ToRemove;
70
- }
71
-
72
- public AnimationsManager(
73
- ReactContext context, UIImplementation uiImplementation, UIManagerModule uiManagerModule) {
54
+ public AnimationsManager(ReactContext context, UIManagerModule uiManagerModule) {
74
55
  mContext = context;
75
- mUIImplementation = uiImplementation;
76
56
  mUIManager = uiManagerModule;
77
- mStates = new HashMap<>();
78
- mViewForTag = new HashMap<>();
79
- mToRemove = new HashSet<>();
80
- mViewManager = new HashMap<>();
81
- mParentViewManager = new HashMap<>();
82
- mParent = new HashMap();
83
- mCallbacks = new HashMap<>();
84
57
  isCatalystInstanceDestroyed = false;
85
58
  }
86
59
 
@@ -88,41 +61,24 @@ public class AnimationsManager implements ViewHierarchyObserver {
88
61
  isCatalystInstanceDestroyed = true;
89
62
  mNativeMethodsHolder = null;
90
63
  mContext = null;
91
- mUIImplementation = null;
92
64
  mUIManager = null;
93
- mStates = null;
94
- mToRemove = null;
95
- mViewForTag = null;
96
- mViewManager = null;
97
- mParent = null;
98
- mParentViewManager = null;
65
+ mExitingViews = null;
66
+ mExitingSubviewCountMap = null;
67
+ mAncestorsToRemove = null;
99
68
  mCallbacks = null;
100
69
  }
101
70
 
102
71
  @Override
103
- public void onViewRemoval(View view, ViewGroup parent, Snapshot before, Runnable callback) {
72
+ public void onViewRemoval(View view, ViewGroup parent, Runnable callback) {
104
73
  if (isCatalystInstanceDestroyed) {
105
74
  return;
106
75
  }
107
76
  Integer tag = view.getId();
108
- HashMap<String, Object> currentValues = before.toCurrentMap();
109
- ViewState state = mStates.get(view.getId());
110
-
111
- if (state == ViewState.Disappearing || state == ViewState.ToRemove) {
112
- return;
113
- }
114
77
  mCallbacks.put(tag, callback);
115
- if (state == ViewState.Inactive || state == null) {
116
- if (currentValues != null) {
117
- mStates.put(view.getId(), ViewState.ToRemove);
118
- mToRemove.add(view.getId());
119
- scheduleCleaning();
120
- }
121
- return;
78
+
79
+ if (!removeOrAnimateExitRecursive(view, parent, true)) {
80
+ removeView(view, parent);
122
81
  }
123
- mStates.put(tag, ViewState.Disappearing);
124
- HashMap<String, Float> preparedValues = prepareDataForAnimationWorklet(currentValues, false);
125
- mNativeMethodsHolder.startAnimationForTag(tag, "exiting", preparedValues);
126
82
  }
127
83
 
128
84
  @Override
@@ -130,27 +86,21 @@ public class AnimationsManager implements ViewHierarchyObserver {
130
86
  if (isCatalystInstanceDestroyed) {
131
87
  return;
132
88
  }
89
+
90
+ if (!hasAnimationForTag(view.getId(), "entering")) {
91
+ return;
92
+ }
93
+
133
94
  Scheduler strongScheduler = mScheduler.get();
134
95
  if (strongScheduler != null) {
135
96
  strongScheduler.triggerUI();
136
97
  }
137
- if (!mStates.containsKey(view.getId())) {
138
- mStates.put(view.getId(), ViewState.Inactive);
139
- mViewForTag.put(view.getId(), view);
140
- mViewManager.put(view.getId(), after.viewManager);
141
- mParentViewManager.put(view.getId(), after.parentViewManager);
142
- mParent.put(view.getId(), after.parent);
143
- }
144
- Integer tag = view.getId();
98
+ int tag = view.getId();
145
99
  HashMap<String, Object> targetValues = after.toTargetMap();
146
- ViewState state = mStates.get(view.getId());
147
100
 
148
- if (state == ViewState.Inactive) { // it can be a fresh view
149
- if (targetValues != null) {
150
- HashMap<String, Float> preparedValues = prepareDataForAnimationWorklet(targetValues, true);
151
- mNativeMethodsHolder.startAnimationForTag(tag, "entering", preparedValues);
152
- }
153
- return;
101
+ if (targetValues != null) {
102
+ HashMap<String, Float> preparedValues = prepareDataForAnimationWorklet(targetValues, true);
103
+ mNativeMethodsHolder.startAnimation(tag, "entering", preparedValues);
154
104
  }
155
105
  }
156
106
 
@@ -159,36 +109,32 @@ public class AnimationsManager implements ViewHierarchyObserver {
159
109
  if (isCatalystInstanceDestroyed) {
160
110
  return;
161
111
  }
162
- Integer tag = view.getId();
163
- HashMap<String, Object> targetValues = after.toTargetMap();
164
- HashMap<String, Object> startValues = before.toCurrentMap();
165
- ViewState state = mStates.get(view.getId());
166
- if (state == null
167
- || state == ViewState.Disappearing
168
- || state == ViewState.ToRemove
169
- || state == ViewState.Inactive) {
112
+ int tag = view.getId();
113
+
114
+ if (!hasAnimationForTag(tag, "layout")) {
170
115
  return;
171
116
  }
117
+
118
+ HashMap<String, Object> targetValues = after.toTargetMap();
119
+ HashMap<String, Object> startValues = before.toCurrentMap();
120
+
172
121
  // If startValues are equal to targetValues it means that there was no UI Operation changing
173
122
  // layout of the View. So dirtiness of that View is false positive
174
- if (state == ViewState.Appearing) {
175
- boolean doNotStartLayout = true;
176
- for (int i = 0; i < Snapshot.targetKeysToTransform.size(); ++i) {
177
- double startV =
178
- ((Number) startValues.get(Snapshot.currentKeysToTransform.get(i))).doubleValue();
179
- double targetV =
180
- ((Number) targetValues.get(Snapshot.targetKeysToTransform.get(i))).doubleValue();
181
- if (startV != targetV) {
182
- doNotStartLayout = false;
183
- }
184
- }
185
- if (doNotStartLayout) {
186
- return;
123
+ boolean doNotStartLayout = true;
124
+ for (int i = 0; i < Snapshot.targetKeysToTransform.size(); ++i) {
125
+ double startV =
126
+ ((Number) startValues.get(Snapshot.currentKeysToTransform.get(i))).doubleValue();
127
+ double targetV =
128
+ ((Number) targetValues.get(Snapshot.targetKeysToTransform.get(i))).doubleValue();
129
+ if (startV != targetV) {
130
+ doNotStartLayout = false;
187
131
  }
188
132
  }
133
+ if (doNotStartLayout) {
134
+ return;
135
+ }
189
136
 
190
137
  // View must be in Layout state
191
- mStates.put(view.getId(), ViewState.Layout);
192
138
  HashMap<String, Float> preparedStartValues = prepareDataForAnimationWorklet(startValues, false);
193
139
  HashMap<String, Float> preparedTargetValues =
194
140
  prepareDataForAnimationWorklet(targetValues, true);
@@ -196,60 +142,41 @@ public class AnimationsManager implements ViewHierarchyObserver {
196
142
  for (String key : preparedStartValues.keySet()) {
197
143
  preparedValues.put(key, preparedStartValues.get(key));
198
144
  }
199
- mNativeMethodsHolder.startAnimationForTag(tag, "layout", preparedValues);
145
+ mNativeMethodsHolder.startAnimation(tag, "layout", preparedValues);
200
146
  }
201
147
 
202
- public void notifyAboutProgress(Map<String, Object> newStyle, Integer tag) {
203
- ViewState state = mStates.get(tag);
204
- if (state == ViewState.Inactive) {
205
- mStates.put(tag, ViewState.Appearing);
206
- }
148
+ public void progressLayoutAnimation(int tag, Map<String, Object> newStyle) {
149
+ View view = resolveView(tag);
207
150
 
208
- setNewProps(
209
- newStyle,
210
- mViewForTag.get(tag),
211
- mViewManager.get(tag),
212
- mParentViewManager.get(tag),
213
- mParent.get(tag).getId());
214
- }
151
+ if (view == null) {
152
+ return;
153
+ }
215
154
 
216
- public void notifyAboutEnd(int tag, boolean cancelled) {
217
- if (!cancelled) {
218
- ViewState state = mStates.get(tag);
219
- if (state == ViewState.Appearing) {
220
- mStates.put(tag, ViewState.Layout);
221
- }
155
+ ViewGroup parent = (ViewGroup) view.getParent();
222
156
 
223
- if (state == ViewState.Disappearing) {
224
- mStates.put(tag, ViewState.ToRemove);
225
- mToRemove.add(tag);
226
- scheduleCleaning();
227
- }
157
+ if (parent == null) {
158
+ return;
228
159
  }
160
+
161
+ ViewManager viewManager = resolveViewManager(tag);
162
+ ViewManager parentViewManager = resolveViewManager(parent.getId());
163
+
164
+ setNewProps(newStyle, view, viewManager, parentViewManager, parent.getId());
229
165
  }
230
166
 
231
- private void removeLeftovers() {
232
- // mToRemove may be null if onCatalystInstanceDestroy was called first
233
- if (mToRemove != null) {
234
- HashSet<Integer> roots = new HashSet<>();
235
- // go through ready to remove from bottom to top
236
- for (int tag : mToRemove) {
237
- View view = mViewForTag.get(tag);
238
- if (view == null) {
239
- try {
240
- view = mUIManager.resolveView(tag);
241
- mViewForTag.put(tag, view);
242
- } catch (IllegalViewOperationException ignored) {
243
- continue;
244
- }
245
- }
246
- findRoot(view, roots);
167
+ public void endLayoutAnimation(int tag, boolean cancelled, boolean removeView) {
168
+ View exitingView = mExitingViews.get(tag);
169
+ if (exitingView != null && removeView) {
170
+ if (exitingView instanceof ViewGroup && mAncestorsToRemove.contains(tag)) {
171
+ cancelAnimationsInSubviews((ViewGroup) exitingView);
247
172
  }
248
- for (int tag : roots) {
249
- View view = mViewForTag.get(tag);
250
- if (view != null) {
251
- dfs(view, view, mToRemove);
252
- }
173
+
174
+ mExitingViews.remove(tag);
175
+ maybeDropAncestors(exitingView);
176
+
177
+ ViewGroup parent = (ViewGroup) exitingView.getParent();
178
+ if (parent != null) {
179
+ removeView(exitingView, parent);
253
180
  }
254
181
  }
255
182
  }
@@ -267,8 +194,6 @@ public class AnimationsManager implements ViewHierarchyObserver {
267
194
  }
268
195
  out.append(" TAG:");
269
196
  out.append(view.getId());
270
- out.append(" STATE:");
271
- out.append(this.mStates.get(view.getId()));
272
197
  out.append(" CLASS:");
273
198
  out.append(view.getClass().getSimpleName());
274
199
  Log.v("rea", out.toString());
@@ -280,85 +205,6 @@ public class AnimationsManager implements ViewHierarchyObserver {
280
205
  }
281
206
  }
282
207
 
283
- private void scheduleCleaning() {
284
- if (mCleaningScheduled) return;
285
- mCleaningScheduled = true;
286
- WeakReference<AnimationsManager> animationsManagerWeakReference = new WeakReference<>(this);
287
- mContext.runOnUiQueueThread(
288
- () -> {
289
- mCleaningScheduled = false;
290
- AnimationsManager thiz = animationsManagerWeakReference.get();
291
- if (thiz == null) {
292
- return;
293
- }
294
- removeLeftovers();
295
- });
296
- }
297
-
298
- private void findRoot(View view, HashSet<Integer> roots) {
299
- View currentView = view;
300
- int lastToRemoveTag = -1;
301
- while (currentView != null) {
302
- ViewState state = mStates.get(currentView.getId());
303
- if (state == ViewState.Disappearing) {
304
- return;
305
- }
306
- if (state == ViewState.ToRemove) {
307
- lastToRemoveTag = currentView.getId();
308
- }
309
- if (currentView.getParent() instanceof View) {
310
- currentView = (View) currentView.getParent();
311
- } else {
312
- break;
313
- }
314
- }
315
- if (lastToRemoveTag != -1) {
316
- roots.add(lastToRemoveTag);
317
- }
318
- }
319
-
320
- private boolean dfs(View root, View view, HashSet<Integer> cands) {
321
- if ((!cands.contains(view.getId())) && (mStates.containsKey(view.getId()))) {
322
- return true;
323
- }
324
- boolean cannotStripe = false;
325
- if (view instanceof ViewGroup && mViewManager.get(view.getId()) instanceof ViewGroupManager) {
326
- ViewGroup vg = (ViewGroup) view;
327
- ViewGroupManager vgm = (ViewGroupManager) mViewManager.get(vg.getId());
328
- ArrayList<View> children = new ArrayList<>();
329
- for (int i = 0; i < vgm.getChildCount(vg); ++i) {
330
- children.add(vgm.getChildAt(vg, i));
331
- }
332
- for (View child : children) {
333
- cannotStripe = cannotStripe || dfs(root, child, cands);
334
- }
335
- }
336
-
337
- if (!cannotStripe) {
338
- View parentView = (View) view.getParent();
339
- if (mCallbacks.containsKey(view.getId())) {
340
- Runnable runnable = mCallbacks.get(view.getId());
341
- mCallbacks.remove(view.getId());
342
- runnable.run();
343
- }
344
- if (mParent.containsKey(view.getId())) {
345
- ViewGroup parent = (ViewGroup) mParent.get(view.getId());
346
- if (parent != null) {
347
- parent.removeView(view);
348
- }
349
- }
350
- View curView = view;
351
- mStates.remove(curView.getId());
352
- mViewForTag.remove(curView.getId());
353
- mViewManager.remove(curView.getId());
354
- mParentViewManager.remove(curView.getId());
355
- mParent.remove(curView.getId());
356
- mNativeMethodsHolder.removeConfigForTag(curView.getId());
357
- mToRemove.remove(view.getId());
358
- }
359
- return cannotStripe;
360
- }
361
-
362
208
  public HashMap<String, Float> prepareDataForAnimationWorklet(
363
209
  HashMap<String, Object> values, boolean isTargetValues) {
364
210
  HashMap<String, Float> preparedValues = new HashMap<>();
@@ -449,7 +295,7 @@ public class AnimationsManager implements ViewHierarchyObserver {
449
295
  } else if (value instanceof ReadableMap) {
450
296
  propMap.putMap(key, (ReadableMap) value);
451
297
  } else {
452
- throw new IllegalStateException("Unknown type of animated value [Layout Aniamtions]");
298
+ throw new IllegalStateException("Unknown type of animated value [Layout Animations]");
453
299
  }
454
300
  }
455
301
 
@@ -512,8 +358,7 @@ public class AnimationsManager implements ViewHierarchyObserver {
512
358
  + parentTag
513
359
  + " as a parent, but its Manager doesn't implement IViewManagerWithChildren");
514
360
  }
515
- if (parentViewManagerWithChildren != null
516
- && !parentViewManagerWithChildren.needsCustomLayoutForChildren()) {
361
+ if (!parentViewManagerWithChildren.needsCustomLayoutForChildren()) {
517
362
  viewToUpdate.layout(x, y, x + width, y + height);
518
363
  }
519
364
  } else {
@@ -521,7 +366,147 @@ public class AnimationsManager implements ViewHierarchyObserver {
521
366
  }
522
367
  }
523
368
 
369
+ public boolean hasAnimationForTag(int tag, String type) {
370
+ return mNativeMethodsHolder.hasAnimation(tag, type);
371
+ }
372
+
524
373
  public boolean isLayoutAnimationEnabled() {
525
374
  return mNativeMethodsHolder != null && mNativeMethodsHolder.isLayoutAnimationEnabled();
526
375
  }
376
+
377
+ private boolean removeOrAnimateExitRecursive(View view, ViewGroup parent, boolean shouldRemove) {
378
+ int tag = view.getId();
379
+ boolean hasExitAnimation = hasAnimationForTag(tag, "exiting") || mExitingViews.containsKey(tag);
380
+ boolean hasAnimatedChildren = false;
381
+ shouldRemove = shouldRemove && !hasExitAnimation;
382
+
383
+ ArrayList<View> toBeRemoved = new ArrayList<>();
384
+
385
+ // we might want to keep this view around
386
+ // because one of the (children's) children
387
+ // has an exiting animation
388
+ if (view instanceof ViewGroup) {
389
+ ViewGroup viewGroup = (ViewGroup) view;
390
+ for (int i = viewGroup.getChildCount() - 1; i >= 0; i--) {
391
+ View child = viewGroup.getChildAt(i);
392
+ if (removeOrAnimateExitRecursive(child, viewGroup, shouldRemove)) {
393
+ hasAnimatedChildren = true;
394
+ } else if (shouldRemove) {
395
+ toBeRemoved.add(child);
396
+ }
397
+ }
398
+ }
399
+
400
+ boolean wantAnimateExit = hasExitAnimation || hasAnimatedChildren;
401
+
402
+ if (hasExitAnimation) {
403
+ Snapshot before = new Snapshot(view, mReanimatedNativeHierarchyManager);
404
+ HashMap<String, Object> currentValues = before.toCurrentMap();
405
+ HashMap<String, Float> preparedValues = prepareDataForAnimationWorklet(currentValues, false);
406
+ if (!mExitingViews.containsKey(tag)) {
407
+ mExitingViews.put(tag, view);
408
+ registerExitingAncestors(view);
409
+ mNativeMethodsHolder.startAnimation(tag, "exiting", preparedValues);
410
+ }
411
+ }
412
+
413
+ mNativeMethodsHolder.clearAnimationConfig(tag);
414
+
415
+ if (!wantAnimateExit) {
416
+ return false;
417
+ }
418
+
419
+ if (hasAnimatedChildren) {
420
+ mAncestorsToRemove.add(tag);
421
+ }
422
+
423
+ for (View child : toBeRemoved) {
424
+ removeView(child, (ViewGroup) view);
425
+ }
426
+
427
+ return true;
428
+ }
429
+
430
+ private void registerExitingAncestors(View view) {
431
+ View parent = (View) view.getParent();
432
+ while (parent != null && !(parent instanceof RootView)) {
433
+ int tag = parent.getId();
434
+ Integer previousValue = mExitingSubviewCountMap.get(tag);
435
+ int newValue = previousValue != null ? previousValue + 1 : 1;
436
+ mExitingSubviewCountMap.put(tag, newValue);
437
+
438
+ parent = (View) parent.getParent();
439
+ }
440
+ }
441
+
442
+ private void maybeDropAncestors(View exitingView) {
443
+ View parent = (View) exitingView.getParent();
444
+ while (parent != null && !(parent instanceof RootView)) {
445
+ View view = parent;
446
+ parent = (View) view.getParent();
447
+ int tag = view.getId();
448
+ Integer ancestorOfCount = mExitingSubviewCountMap.get(tag);
449
+ ancestorOfCount = ancestorOfCount != null ? ancestorOfCount - 1 : 0;
450
+ if (ancestorOfCount <= 0) {
451
+ if (mAncestorsToRemove.contains(tag)) {
452
+ mAncestorsToRemove.remove(tag);
453
+ if (!mExitingViews.containsKey(tag)) {
454
+ removeView(view, (ViewGroup) parent);
455
+ }
456
+ }
457
+ mExitingSubviewCountMap.remove(tag);
458
+ } else {
459
+ mExitingSubviewCountMap.put(tag, ancestorOfCount);
460
+ }
461
+ }
462
+ }
463
+
464
+ private void removeView(View view, ViewGroup parent) {
465
+ int tag = view.getId();
466
+ if (mCallbacks.containsKey(tag)) {
467
+ Runnable callback = mCallbacks.get(tag);
468
+ mCallbacks.remove(tag);
469
+ if (callback != null) {
470
+ callback.run();
471
+ }
472
+ } else {
473
+ mReanimatedNativeHierarchyManager.publicDropView(view);
474
+ }
475
+
476
+ parent.removeView(view);
477
+ }
478
+
479
+ private void cancelAnimationsInSubviews(ViewGroup view) {
480
+ for (int i = view.getChildCount() - 1; i >= 0; i--) {
481
+ View child = view.getChildAt(i);
482
+
483
+ if (mExitingViews.containsKey(child.getId())) {
484
+ endLayoutAnimation(child.getId(), true, true);
485
+ } else if (child instanceof ViewGroup && mAncestorsToRemove.contains(child.getId())) {
486
+ cancelAnimationsInSubviews((ViewGroup) child);
487
+ }
488
+ }
489
+ }
490
+
491
+ private View resolveView(int tag) {
492
+ if (mExitingViews.containsKey(tag)) {
493
+ return mExitingViews.get(tag);
494
+ }
495
+ try {
496
+ return mUIManager.resolveView(tag);
497
+ } catch (IllegalViewOperationException e) {
498
+ // view has been removed already
499
+ e.printStackTrace();
500
+ return null;
501
+ }
502
+ }
503
+
504
+ private ViewManager resolveViewManager(int tag) {
505
+ try {
506
+ return mReanimatedNativeHierarchyManager.resolveViewManager(tag);
507
+ } catch (Exception e) {
508
+ e.printStackTrace();
509
+ return null;
510
+ }
511
+ }
527
512
  }
@@ -29,29 +29,31 @@ public class LayoutAnimations {
29
29
  // LayoutReanimation
30
30
  public native void startAnimationForTag(int tag, String type, Map<String, String> values);
31
31
 
32
- public native void removeConfigForTag(int tag);
32
+ public native boolean hasAnimationForTag(int tag, String type);
33
+
34
+ public native void clearAnimationConfigForTag(int tag);
33
35
 
34
36
  public native boolean isLayoutAnimationEnabled();
35
37
 
36
- private void notifyAboutEnd(int tag, int cancelledInt) {
38
+ private void endLayoutAnimation(int tag, boolean cancelled, boolean removeView) {
37
39
  ReactApplicationContext context = mContext.get();
38
40
  if (context != null) {
39
41
  context
40
42
  .getNativeModule(ReanimatedModule.class)
41
43
  .getNodesManager()
42
44
  .getAnimationsManager()
43
- .notifyAboutEnd(tag, (cancelledInt == 0) ? false : true);
45
+ .endLayoutAnimation(tag, cancelled, removeView);
44
46
  }
45
47
  }
46
48
 
47
- private void notifyAboutProgress(Map<String, Object> newStyle, int tag) {
49
+ private void progressLayoutAnimation(int tag, Map<String, Object> newStyle) {
48
50
  ReactApplicationContext context = mContext.get();
49
51
  if (context != null) {
50
52
  context
51
53
  .getNativeModule(ReanimatedModule.class)
52
54
  .getNodesManager()
53
55
  .getAnimationsManager()
54
- .notifyAboutProgress(newStyle, tag);
56
+ .progressLayoutAnimation(tag, newStyle);
55
57
  }
56
58
  }
57
59
  }