react-native-reanimated 3.13.0-rc.2 → 3.13.0

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 (153) hide show
  1. package/Common/cpp/LayoutAnimations/LayoutAnimationsManager.cpp +8 -2
  2. package/Common/cpp/LayoutAnimations/LayoutAnimationsManager.h +3 -1
  3. package/Common/cpp/LayoutAnimations/LayoutAnimationsProxy.cpp +58 -33
  4. package/Common/cpp/LayoutAnimations/LayoutAnimationsProxy.h +19 -9
  5. package/Common/cpp/LayoutAnimations/LayoutAnimationsUtils.cpp +11 -7
  6. package/Common/cpp/LayoutAnimations/LayoutAnimationsUtils.h +14 -6
  7. package/Common/cpp/NativeModules/NativeReanimatedModule.cpp +1 -1
  8. package/Common/cpp/NativeModules/NativeReanimatedModule.h +1 -1
  9. package/Common/cpp/ReanimatedRuntime/WorkletRuntime.cpp +1 -1
  10. package/Common/cpp/ReanimatedRuntime/WorkletRuntime.h +1 -1
  11. package/Common/cpp/ReanimatedRuntime/WorkletRuntimeDecorator.cpp +6 -6
  12. package/Common/cpp/SharedItems/Shareables.cpp +25 -8
  13. package/Common/cpp/SharedItems/Shareables.h +12 -7
  14. package/android/CMakeLists.txt +1 -1
  15. package/android/src/main/cpp/LayoutAnimations.cpp +14 -0
  16. package/android/src/main/cpp/LayoutAnimations.h +5 -0
  17. package/android/src/main/cpp/NativeProxy.cpp +10 -0
  18. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/AnimationsManager.java +10 -2
  19. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/LayoutAnimations.java +2 -0
  20. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/NativeMethodsHolder.java +2 -0
  21. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/ReanimatedNativeHierarchyManager.java +10 -0
  22. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/ScreensHelper.java +83 -0
  23. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/SharedTransitionManager.java +130 -31
  24. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/Snapshot.java +36 -0
  25. package/android/src/main/java/com/swmansion/reanimated/layoutReanimation/TabNavigatorObserver.java +128 -0
  26. package/android/src/paper/java/com/swmansion/reanimated/NativeProxy.java +8 -0
  27. package/android/src/reactNativeVersionPatch/RuntimeExecutor/73/com/swmansion/reanimated/NativeProxy.java +6 -0
  28. package/android/src/reactNativeVersionPatch/RuntimeExecutor/latest/com/swmansion/reanimated/NativeProxy.java +6 -0
  29. package/apple/LayoutReanimation/REAAnimationsManager.h +2 -0
  30. package/apple/LayoutReanimation/REAAnimationsManager.m +5 -0
  31. package/apple/LayoutReanimation/REAScreensHelper.h +6 -0
  32. package/apple/LayoutReanimation/REAScreensHelper.m +92 -4
  33. package/apple/LayoutReanimation/REASharedTransitionManager.h +1 -0
  34. package/apple/LayoutReanimation/REASharedTransitionManager.m +254 -55
  35. package/apple/native/NativeProxy.mm +12 -0
  36. package/lib/module/Colors.js +5 -2
  37. package/lib/module/Colors.js.map +1 -1
  38. package/lib/module/UpdateProps.js +8 -8
  39. package/lib/module/UpdateProps.js.map +1 -1
  40. package/lib/module/ViewDescriptorsSet.js +0 -27
  41. package/lib/module/ViewDescriptorsSet.js.map +1 -1
  42. package/lib/module/createAnimatedComponent/InlinePropManager.js +1 -7
  43. package/lib/module/createAnimatedComponent/InlinePropManager.js.map +1 -1
  44. package/lib/module/createAnimatedComponent/PropsFilter.js +1 -6
  45. package/lib/module/createAnimatedComponent/PropsFilter.js.map +1 -1
  46. package/lib/module/createAnimatedComponent/commonTypes.js.map +1 -1
  47. package/lib/module/createAnimatedComponent/createAnimatedComponent.js +1 -5
  48. package/lib/module/createAnimatedComponent/createAnimatedComponent.js.map +1 -1
  49. package/lib/module/hook/commonTypes.js.map +1 -1
  50. package/lib/module/hook/useAnimatedStyle.js +12 -15
  51. package/lib/module/hook/useAnimatedStyle.js.map +1 -1
  52. package/lib/module/hook/useFrameCallback.js +2 -2
  53. package/lib/module/hook/useFrameCallback.js.map +1 -1
  54. package/lib/module/hook/useWorkletCallback.js +1 -1
  55. package/lib/module/hook/useWorkletCallback.js.map +1 -1
  56. package/lib/module/js-reanimated/index.js +3 -28
  57. package/lib/module/js-reanimated/index.js.map +1 -1
  58. package/lib/module/js-reanimated/webUtils.js +9 -0
  59. package/lib/module/js-reanimated/webUtils.js.map +1 -0
  60. package/lib/module/js-reanimated/webUtils.web.js +25 -0
  61. package/lib/module/js-reanimated/webUtils.web.js.map +1 -0
  62. package/lib/module/layoutReanimation/defaultTransitions/CurvedTransition.js +1 -0
  63. package/lib/module/layoutReanimation/defaultTransitions/CurvedTransition.js.map +1 -1
  64. package/lib/module/layoutReanimation/defaultTransitions/EntryExitTransition.js +1 -0
  65. package/lib/module/layoutReanimation/defaultTransitions/EntryExitTransition.js.map +1 -1
  66. package/lib/module/layoutReanimation/defaultTransitions/FadingTransition.js +11 -10
  67. package/lib/module/layoutReanimation/defaultTransitions/FadingTransition.js.map +1 -1
  68. package/lib/module/layoutReanimation/defaultTransitions/JumpingTransition.js +1 -0
  69. package/lib/module/layoutReanimation/defaultTransitions/JumpingTransition.js.map +1 -1
  70. package/lib/module/layoutReanimation/defaultTransitions/LinearTransition.js +1 -0
  71. package/lib/module/layoutReanimation/defaultTransitions/LinearTransition.js.map +1 -1
  72. package/lib/module/layoutReanimation/defaultTransitions/SequencedTransition.js +1 -0
  73. package/lib/module/layoutReanimation/defaultTransitions/SequencedTransition.js.map +1 -1
  74. package/lib/module/layoutReanimation/web/Easing.web.js +14 -0
  75. package/lib/module/layoutReanimation/web/Easing.web.js.map +1 -0
  76. package/lib/module/layoutReanimation/web/animationParser.js +16 -1
  77. package/lib/module/layoutReanimation/web/animationParser.js.map +1 -1
  78. package/lib/module/layoutReanimation/web/animationsManager.js +25 -8
  79. package/lib/module/layoutReanimation/web/animationsManager.js.map +1 -1
  80. package/lib/module/layoutReanimation/web/componentStyle.js +12 -16
  81. package/lib/module/layoutReanimation/web/componentStyle.js.map +1 -1
  82. package/lib/module/layoutReanimation/web/componentUtils.js +53 -18
  83. package/lib/module/layoutReanimation/web/componentUtils.js.map +1 -1
  84. package/lib/module/layoutReanimation/web/config.js +1 -12
  85. package/lib/module/layoutReanimation/web/config.js.map +1 -1
  86. package/lib/module/layoutReanimation/web/createAnimation.js +21 -2
  87. package/lib/module/layoutReanimation/web/createAnimation.js.map +1 -1
  88. package/lib/module/layoutReanimation/web/domUtils.js +6 -5
  89. package/lib/module/layoutReanimation/web/domUtils.js.map +1 -1
  90. package/lib/module/layoutReanimation/web/transition/Jumping.web.js +43 -0
  91. package/lib/module/layoutReanimation/web/transition/Jumping.web.js.map +1 -0
  92. package/lib/module/platform-specific/RNRenderer.web.js +1 -1
  93. package/lib/module/platform-specific/RNRenderer.web.js.map +1 -1
  94. package/lib/module/platform-specific/jsVersion.js +1 -1
  95. package/lib/module/platform-specific/jsVersion.js.map +1 -1
  96. package/lib/module/platformFunctions/setNativeProps.web.js +1 -3
  97. package/lib/module/platformFunctions/setNativeProps.web.js.map +1 -1
  98. package/lib/typescript/UpdateProps.d.ts +2 -3
  99. package/lib/typescript/ViewDescriptorsSet.d.ts +0 -9
  100. package/lib/typescript/createAnimatedComponent/commonTypes.d.ts +1 -2
  101. package/lib/typescript/hook/commonTypes.d.ts +3 -6
  102. package/lib/typescript/hook/useWorkletCallback.d.ts +1 -1
  103. package/lib/typescript/js-reanimated/index.d.ts +2 -4
  104. package/lib/typescript/js-reanimated/webUtils.d.ts +3 -0
  105. package/lib/typescript/js-reanimated/webUtils.web.d.ts +3 -0
  106. package/lib/typescript/layoutReanimation/defaultTransitions/CurvedTransition.d.ts +1 -0
  107. package/lib/typescript/layoutReanimation/defaultTransitions/EntryExitTransition.d.ts +1 -0
  108. package/lib/typescript/layoutReanimation/defaultTransitions/FadingTransition.d.ts +1 -0
  109. package/lib/typescript/layoutReanimation/defaultTransitions/JumpingTransition.d.ts +1 -0
  110. package/lib/typescript/layoutReanimation/defaultTransitions/LinearTransition.d.ts +1 -0
  111. package/lib/typescript/layoutReanimation/defaultTransitions/SequencedTransition.d.ts +1 -0
  112. package/lib/typescript/layoutReanimation/web/Easing.web.d.ts +10 -0
  113. package/lib/typescript/layoutReanimation/web/animationParser.d.ts +1 -2
  114. package/lib/typescript/layoutReanimation/web/componentStyle.d.ts +1 -1
  115. package/lib/typescript/layoutReanimation/web/componentUtils.d.ts +4 -3
  116. package/lib/typescript/layoutReanimation/web/config.d.ts +5 -12
  117. package/lib/typescript/layoutReanimation/web/createAnimation.d.ts +2 -0
  118. package/lib/typescript/layoutReanimation/web/domUtils.d.ts +1 -1
  119. package/lib/typescript/layoutReanimation/web/transition/Jumping.web.d.ts +29 -0
  120. package/lib/typescript/platform-specific/jsVersion.d.ts +1 -1
  121. package/package.json +4 -3
  122. package/src/Colors.ts +5 -2
  123. package/src/UpdateProps.ts +8 -11
  124. package/src/ViewDescriptorsSet.ts +0 -42
  125. package/src/createAnimatedComponent/InlinePropManager.ts +2 -8
  126. package/src/createAnimatedComponent/PropsFilter.tsx +0 -4
  127. package/src/createAnimatedComponent/commonTypes.ts +1 -2
  128. package/src/createAnimatedComponent/createAnimatedComponent.tsx +1 -5
  129. package/src/hook/commonTypes.ts +3 -6
  130. package/src/hook/useAnimatedStyle.ts +9 -26
  131. package/src/hook/useFrameCallback.ts +2 -2
  132. package/src/hook/useWorkletCallback.ts +1 -1
  133. package/src/js-reanimated/index.ts +11 -37
  134. package/src/js-reanimated/webUtils.ts +8 -0
  135. package/src/js-reanimated/webUtils.web.ts +27 -0
  136. package/src/layoutReanimation/defaultTransitions/CurvedTransition.ts +2 -0
  137. package/src/layoutReanimation/defaultTransitions/EntryExitTransition.ts +2 -0
  138. package/src/layoutReanimation/defaultTransitions/FadingTransition.ts +12 -10
  139. package/src/layoutReanimation/defaultTransitions/JumpingTransition.ts +2 -0
  140. package/src/layoutReanimation/defaultTransitions/LinearTransition.ts +2 -0
  141. package/src/layoutReanimation/defaultTransitions/SequencedTransition.ts +2 -0
  142. package/src/layoutReanimation/web/Easing.web.ts +15 -0
  143. package/src/layoutReanimation/web/animationParser.ts +30 -2
  144. package/src/layoutReanimation/web/animationsManager.ts +45 -12
  145. package/src/layoutReanimation/web/componentStyle.ts +13 -16
  146. package/src/layoutReanimation/web/componentUtils.ts +68 -25
  147. package/src/layoutReanimation/web/config.ts +5 -14
  148. package/src/layoutReanimation/web/createAnimation.ts +38 -4
  149. package/src/layoutReanimation/web/domUtils.ts +15 -5
  150. package/src/layoutReanimation/web/transition/Jumping.web.ts +44 -0
  151. package/src/platform-specific/RNRenderer.web.ts +1 -1
  152. package/src/platform-specific/jsVersion.ts +1 -1
  153. package/src/platformFunctions/setNativeProps.web.ts +1 -1
@@ -1,4 +1,5 @@
1
1
  #include "LayoutAnimations.h"
2
+ #include <vector>
2
3
  #include "FeaturesConfig.h"
3
4
  #include "Logger.h"
4
5
 
@@ -100,10 +101,22 @@ void LayoutAnimations::setFindPrecedingViewTagForTransition(
100
101
  findPrecedingViewTagForTransitionBlock;
101
102
  }
102
103
 
104
+ void LayoutAnimations::setGetSharedGroupBlock(
105
+ GetSharedGroupBlock getSharedGroupBlock) {
106
+ getSharedGroupBlock_ = getSharedGroupBlock;
107
+ }
108
+
103
109
  int LayoutAnimations::findPrecedingViewTagForTransition(int tag) {
104
110
  return findPrecedingViewTagForTransitionBlock_(tag);
105
111
  }
106
112
 
113
+ jni::local_ref<JArrayInt> LayoutAnimations::getSharedGroup(const int tag) {
114
+ const auto &group = getSharedGroupBlock_(tag);
115
+ auto jGroup = JArrayInt::newArray(group.size());
116
+ jGroup->setRegion(0, group.size(), group.data());
117
+ return jGroup;
118
+ }
119
+
107
120
  void LayoutAnimations::registerNatives() {
108
121
  registerHybrid({
109
122
  makeNativeMethod("initHybrid", LayoutAnimations::initHybrid),
@@ -124,6 +137,7 @@ void LayoutAnimations::registerNatives() {
124
137
  makeNativeMethod(
125
138
  "findPrecedingViewTagForTransition",
126
139
  LayoutAnimations::findPrecedingViewTagForTransition),
140
+ makeNativeMethod("getSharedGroup", LayoutAnimations::getSharedGroup),
127
141
  #ifndef NDEBUG
128
142
  makeNativeMethod(
129
143
  "checkDuplicateSharedTag", LayoutAnimations::checkDuplicateSharedTag),
@@ -4,6 +4,7 @@
4
4
  #include <jsi/jsi.h>
5
5
  #include <memory>
6
6
  #include <string>
7
+ #include <vector>
7
8
  #include "JNIHelper.h"
8
9
 
9
10
  namespace reanimated {
@@ -22,6 +23,7 @@ class LayoutAnimations : public jni::HybridClass<LayoutAnimations> {
22
23
  using ClearAnimationConfigBlock = std::function<void(int)>;
23
24
  using CancelAnimationBlock = std::function<void(int)>;
24
25
  using FindPrecedingViewTagForTransitionBlock = std::function<int(int)>;
26
+ using GetSharedGroupBlock = std::function<std::vector<int>(const int)>;
25
27
 
26
28
  public:
27
29
  static auto constexpr kJavaDescriptor =
@@ -53,6 +55,7 @@ class LayoutAnimations : public jni::HybridClass<LayoutAnimations> {
53
55
  void setFindPrecedingViewTagForTransition(
54
56
  FindPrecedingViewTagForTransitionBlock
55
57
  findPrecedingViewTagForTransitionBlock);
58
+ void setGetSharedGroupBlock(const GetSharedGroupBlock getSharedGroupBlock);
56
59
 
57
60
  void progressLayoutAnimation(
58
61
  int tag,
@@ -62,6 +65,7 @@ class LayoutAnimations : public jni::HybridClass<LayoutAnimations> {
62
65
  void clearAnimationConfigForTag(int tag);
63
66
  void cancelAnimationForTag(int tag);
64
67
  int findPrecedingViewTagForTransition(int tag);
68
+ jni::local_ref<JArrayInt> getSharedGroup(const int tag);
65
69
 
66
70
  private:
67
71
  friend HybridBase;
@@ -73,6 +77,7 @@ class LayoutAnimations : public jni::HybridClass<LayoutAnimations> {
73
77
  CancelAnimationBlock cancelAnimationBlock_;
74
78
  FindPrecedingViewTagForTransitionBlock
75
79
  findPrecedingViewTagForTransitionBlock_;
80
+ GetSharedGroupBlock getSharedGroupBlock_;
76
81
  #ifndef NDEBUG
77
82
  CheckDuplicateSharedTag checkDuplicateSharedTag_;
78
83
  #endif
@@ -652,6 +652,16 @@ void NativeProxy::setupLayoutAnimations() {
652
652
  return -1;
653
653
  }
654
654
  });
655
+
656
+ layoutAnimations_->cthis()->setGetSharedGroupBlock(
657
+ [weakNativeReanimatedModule](int tag) -> std::vector<int> {
658
+ if (auto nativeReanimatedModule = weakNativeReanimatedModule.lock()) {
659
+ return nativeReanimatedModule->layoutAnimationsManager()
660
+ .getSharedGroup(tag);
661
+ } else {
662
+ return {};
663
+ }
664
+ });
655
665
  }
656
666
 
657
667
  } // namespace reanimated
@@ -494,7 +494,7 @@ public class AnimationsManager implements ViewHierarchyObserver {
494
494
  }
495
495
 
496
496
  public boolean hasAnimationForTag(int tag, int type) {
497
- return mNativeMethodsHolder.hasAnimation(tag, type);
497
+ return mNativeMethodsHolder != null && mNativeMethodsHolder.hasAnimation(tag, type);
498
498
  }
499
499
 
500
500
  public boolean isLayoutAnimationEnabled() {
@@ -680,7 +680,7 @@ public class AnimationsManager implements ViewHierarchyObserver {
680
680
  }
681
681
  }
682
682
 
683
- private View resolveView(int tag) {
683
+ protected View resolveView(int tag) {
684
684
  if (mExitingViews.containsKey(tag)) {
685
685
  return mExitingViews.get(tag);
686
686
  } else {
@@ -718,6 +718,14 @@ public class AnimationsManager implements ViewHierarchyObserver {
718
718
  mSharedTransitionManager.screenDidLayout(view);
719
719
  }
720
720
 
721
+ public void navigationTabChanged(View previousTab, View newTab) {
722
+ mSharedTransitionManager.navigationTabChanged(previousTab, newTab);
723
+ }
724
+
725
+ public void visitNativeTreeAndMakeSnapshot(View view) {
726
+ mSharedTransitionManager.visitNativeTreeAndMakeSnapshot(view);
727
+ }
728
+
721
729
  public void viewDidLayout(View view) {
722
730
  mSharedTransitionManager.viewDidLayout(view);
723
731
  }
@@ -52,6 +52,8 @@ public class LayoutAnimations {
52
52
 
53
53
  public native int findPrecedingViewTagForTransition(int tag);
54
54
 
55
+ public native int[] getSharedGroup(int tag);
56
+
55
57
  private void endLayoutAnimation(int tag, boolean removeView) {
56
58
  AnimationsManager animationsManager = getAnimationsManager();
57
59
  if (animationsManager == null) {
@@ -18,4 +18,6 @@ public interface NativeMethodsHolder {
18
18
  int findPrecedingViewTagForTransition(int tag);
19
19
 
20
20
  void checkDuplicateSharedTag(int viewTag, int screenTag);
21
+
22
+ int[] getSharedGroup(int viewTag);
21
23
  }
@@ -214,12 +214,14 @@ public class ReanimatedNativeHierarchyManager extends NativeViewHierarchyManager
214
214
  private final ReaLayoutAnimator mReaLayoutAnimator;
215
215
  private final HashMap<Integer, Set<Integer>> mPendingDeletionsForTag = new HashMap<>();
216
216
  private boolean initOk = true;
217
+ private final TabNavigatorObserver mTabNavigatorObserver;
217
218
 
218
219
  public ReanimatedNativeHierarchyManager(
219
220
  ViewManagerRegistry viewManagers, ReactApplicationContext reactContext) {
220
221
  super(viewManagers);
221
222
 
222
223
  mReaLayoutAnimator = new ReaLayoutAnimator(reactContext, this);
224
+ mTabNavigatorObserver = new TabNavigatorObserver(mReaLayoutAnimator);
223
225
 
224
226
  Class<?> clazz = this.getClass().getSuperclass();
225
227
  if (clazz == null) {
@@ -293,6 +295,14 @@ public class ReanimatedNativeHierarchyManager extends NativeViewHierarchyManager
293
295
  if (!hasHeader || !container.isLayoutRequested()) {
294
296
  mReaLayoutAnimator.getAnimationsManager().screenDidLayout(container);
295
297
  }
298
+ View screen = resolveView(tag);
299
+ View screenFragmentManager = (View) screen.getParent();
300
+ if (screenFragmentManager != null) {
301
+ View screenHolder = (View) screenFragmentManager.getParent();
302
+ if (ScreensHelper.isScreenContainer(screenHolder)) {
303
+ mTabNavigatorObserver.handleScreenContainerUpdate(screen);
304
+ }
305
+ }
296
306
  }
297
307
  View view = resolveView(tag);
298
308
  if (view != null && mReaLayoutAnimator != null) {
@@ -0,0 +1,83 @@
1
+ package com.swmansion.reanimated.layoutReanimation;
2
+
3
+ import android.util.Log;
4
+ import android.view.View;
5
+ import java.lang.reflect.InvocationTargetException;
6
+ import java.lang.reflect.Method;
7
+
8
+ public class ScreensHelper {
9
+
10
+ public static View getTabNavigator(View view) {
11
+ View currentView = view;
12
+ while (currentView != null) {
13
+ if (isScreenContainer(currentView)) {
14
+ return currentView;
15
+ }
16
+ if (isScreen(currentView) && isScreensCoordinatorLayout(currentView.getParent())) {
17
+ View screen = currentView;
18
+ Class<?> screenClass = screen.getClass();
19
+ try {
20
+ Method getContainer = screenClass.getMethod("getContainer");
21
+ currentView = (View) getContainer.invoke(screen);
22
+ } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
23
+ String message =
24
+ e.getMessage() != null ? e.getMessage() : "Unable to invoke the getContainer method";
25
+ Log.e("[Reanimated]", message);
26
+ break;
27
+ }
28
+ } else if (currentView.getParent() instanceof View) {
29
+ currentView = (View) currentView.getParent();
30
+ } else {
31
+ break;
32
+ }
33
+ }
34
+ return null;
35
+ }
36
+
37
+ public static boolean isViewChildOfScreen(View view, View screen) {
38
+ View currentView = view;
39
+ while (currentView != null) {
40
+ if (currentView == screen) {
41
+ return true;
42
+ }
43
+ if (!(currentView.getParent() instanceof View)) {
44
+ return false;
45
+ }
46
+ currentView = (View) currentView.getParent();
47
+ }
48
+ return false;
49
+ }
50
+
51
+ public static View getTopScreenForStack(View view) {
52
+ if (isScreenStack(view)) {
53
+ View stack = view;
54
+ Class<?> screenStackClass = stack.getClass();
55
+ try {
56
+ Method getTopScreen = screenStackClass.getMethod("getTopScreen");
57
+ return (View) getTopScreen.invoke(stack);
58
+ } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ignored) {
59
+ }
60
+ }
61
+ return view;
62
+ }
63
+
64
+ public static boolean isScreen(Object maybeView) {
65
+ return isInstanceOf(maybeView, "Screen");
66
+ }
67
+
68
+ public static boolean isScreenStack(Object maybeView) {
69
+ return isInstanceOf(maybeView, "ScreenStack");
70
+ }
71
+
72
+ public static boolean isScreenContainer(Object maybeView) {
73
+ return isInstanceOf(maybeView, "ScreenContainer");
74
+ }
75
+
76
+ public static boolean isScreensCoordinatorLayout(Object maybeView) {
77
+ return isInstanceOf(maybeView, "ScreensCoordinatorLayout");
78
+ }
79
+
80
+ private static boolean isInstanceOf(Object maybeView, String className) {
81
+ return maybeView != null && maybeView.getClass().getSimpleName().equals(className);
82
+ }
83
+ }
@@ -193,6 +193,11 @@ public class SharedTransitionManager {
193
193
  }
194
194
 
195
195
  protected void onScreenWillDisappear() {
196
+ for (Integer tag : mTagsToCleanup) {
197
+ mNativeMethodsHolder.clearAnimationConfig(tag);
198
+ }
199
+ mTagsToCleanup.clear();
200
+
196
201
  if (!mIsTransitionPrepared) {
197
202
  return;
198
203
  }
@@ -205,11 +210,6 @@ public class SharedTransitionManager {
205
210
  }
206
211
 
207
212
  startPreparedTransitions();
208
-
209
- for (Integer tag : mTagsToCleanup) {
210
- mNativeMethodsHolder.clearAnimationConfig(tag);
211
- }
212
- mTagsToCleanup.clear();
213
213
  }
214
214
 
215
215
  private boolean tryStartSharedTransitionForViews(
@@ -265,17 +265,22 @@ public class SharedTransitionManager {
265
265
  mNativeMethodsHolder.findPrecedingViewTagForTransition(sharedView.getId());
266
266
  }
267
267
  }
268
+
268
269
  boolean bothAreRemoved = !addedNewScreen && viewTags.contains(targetViewTag);
269
270
  if (targetViewTag < 0) {
270
271
  continue;
271
272
  }
273
+
274
+ View siblingView = reanimatedNativeHierarchyManager.resolveView(targetViewTag);
275
+ siblingView = maybeOverrideSiblingForTabNavigator(sharedView, siblingView);
276
+
272
277
  View viewSource, viewTarget;
273
278
  if (addedNewScreen) {
274
- viewSource = reanimatedNativeHierarchyManager.resolveView(targetViewTag);
279
+ viewSource = siblingView;
275
280
  viewTarget = sharedView;
276
281
  } else {
277
282
  viewSource = sharedView;
278
- viewTarget = reanimatedNativeHierarchyManager.resolveView(targetViewTag);
283
+ viewTarget = siblingView;
279
284
  }
280
285
  if (bothAreRemoved) {
281
286
  // case for nested stack
@@ -293,33 +298,43 @@ public class SharedTransitionManager {
293
298
  continue;
294
299
  }
295
300
 
296
- ViewGroup stack = (ViewGroup) findStack(viewSourceScreen);
297
- if (stack == null) {
301
+ ViewGroup sourceStack = (ViewGroup) findStack(viewSourceScreen);
302
+ if (sourceStack == null) {
298
303
  continue;
299
304
  }
300
-
301
- ViewGroupManager stackViewGroupManager =
302
- (ViewGroupManager) reanimatedNativeHierarchyManager.resolveViewManager(stack.getId());
303
- int screensCount = stackViewGroupManager.getChildCount(stack);
304
-
305
- if (screensCount < 2) {
306
- continue;
305
+ int stackId = sourceStack.getId();
306
+ ViewGroupManager stackViewManager =
307
+ (ViewGroupManager) reanimatedNativeHierarchyManager.resolveViewManager(stackId);
308
+ boolean isInSameStack = false;
309
+ for (int i = 0; i < stackViewManager.getChildCount(sourceStack); i++) {
310
+ if (stackViewManager.getChildAt(sourceStack, i) == viewTargetScreen) {
311
+ isInSameStack = true;
312
+ }
307
313
  }
314
+ if (isInSameStack) {
315
+ ViewGroupManager stackViewGroupManager =
316
+ (ViewGroupManager)
317
+ reanimatedNativeHierarchyManager.resolveViewManager(sourceStack.getId());
318
+ int screensCount = stackViewGroupManager.getChildCount(sourceStack);
319
+ if (screensCount < 2) {
320
+ continue;
321
+ }
308
322
 
309
- View topScreen = stackViewGroupManager.getChildAt(stack, screensCount - 1);
310
- View secondScreen = stackViewGroupManager.getChildAt(stack, screensCount - 2);
311
- boolean isValidConfiguration;
312
- if (addedNewScreen) {
313
- isValidConfiguration =
314
- secondScreen.getId() == viewSourceScreen.getId()
315
- && topScreen.getId() == viewTargetScreen.getId();
316
- } else {
317
- isValidConfiguration =
318
- topScreen.getId() == viewSourceScreen.getId()
319
- && secondScreen.getId() == viewTargetScreen.getId();
320
- }
321
- if (!isValidConfiguration) {
322
- continue;
323
+ View topScreen = stackViewGroupManager.getChildAt(sourceStack, screensCount - 1);
324
+ View secondScreen = stackViewGroupManager.getChildAt(sourceStack, screensCount - 2);
325
+ boolean isValidConfiguration;
326
+ if (addedNewScreen) {
327
+ isValidConfiguration =
328
+ secondScreen.getId() == viewSourceScreen.getId()
329
+ && topScreen.getId() == viewTargetScreen.getId();
330
+ } else {
331
+ isValidConfiguration =
332
+ topScreen.getId() == viewSourceScreen.getId()
333
+ && secondScreen.getId() == viewTargetScreen.getId();
334
+ }
335
+ if (!isValidConfiguration) {
336
+ continue;
337
+ }
323
338
  }
324
339
  }
325
340
 
@@ -340,7 +355,7 @@ public class SharedTransitionManager {
340
355
  }
341
356
  Snapshot targetViewSnapshot = mSnapshotRegistry.get(viewTarget.getId());
342
357
  if (targetViewSnapshot == null) {
343
- continue;
358
+ makeSnapshot(viewTarget);
344
359
  }
345
360
 
346
361
  newTransitionViews.add(viewSource);
@@ -379,6 +394,33 @@ public class SharedTransitionManager {
379
394
  return sharedElements;
380
395
  }
381
396
 
397
+ private View maybeOverrideSiblingForTabNavigator(View sharedView, View siblingView) {
398
+ View maybeTabNavigatorForSharedView = ScreensHelper.getTabNavigator(sharedView);
399
+
400
+ if (maybeTabNavigatorForSharedView == null) {
401
+ return siblingView;
402
+ }
403
+
404
+ int siblingTag = siblingView.getId();
405
+ int[] sharedGroup = mNativeMethodsHolder.getSharedGroup(sharedView.getId());
406
+ int siblingIndex = -1;
407
+ for (int i = 0; i < sharedGroup.length; i++) {
408
+ if (sharedGroup[i] == siblingTag) {
409
+ siblingIndex = i;
410
+ }
411
+ }
412
+
413
+ for (int i = siblingIndex; i >= 0; i--) {
414
+ int viewTag = sharedGroup[i];
415
+ View view = mAnimationsManager.resolveView(viewTag);
416
+ if (maybeTabNavigatorForSharedView == ScreensHelper.getTabNavigator(view)) {
417
+ return view;
418
+ }
419
+ }
420
+
421
+ return siblingView;
422
+ }
423
+
382
424
  private void setupTransitionContainer() {
383
425
  if (mTransitionContainer == null) {
384
426
  ReactContext context = mAnimationsManager.getContext();
@@ -640,6 +682,7 @@ public class SharedTransitionManager {
640
682
  }
641
683
 
642
684
  void visitNativeTreeAndMakeSnapshot(View view) {
685
+ view = ScreensHelper.getTopScreenForStack(view);
643
686
  if (!(view instanceof ViewGroup)) {
644
687
  return;
645
688
  }
@@ -696,4 +739,60 @@ public class SharedTransitionManager {
696
739
  }
697
740
  }
698
741
  }
742
+
743
+ public void navigationTabChanged(View previousTab, View newTab) {
744
+ mAddedSharedViews.clear();
745
+ List<SharedElement> sharedElements = new ArrayList<>();
746
+ List<View> sharedViews = new ArrayList<>();
747
+ findSharedViewsForScreen(previousTab, sharedViews);
748
+ sortViewsByTags(sharedViews);
749
+ for (View sharedView : sharedViews) {
750
+ int[] sharedGroup = mNativeMethodsHolder.getSharedGroup(sharedView.getId());
751
+ for (int i = sharedGroup.length - 1; i >= 0; i--) {
752
+ View targetView = mAnimationsManager.resolveView(sharedGroup[i]);
753
+ if (!ScreensHelper.isViewChildOfScreen(targetView, newTab)) {
754
+ continue;
755
+ }
756
+ Snapshot sourceViewSnapshot = mSnapshotRegistry.get(sharedView.getId());
757
+ if (sourceViewSnapshot == null) {
758
+ // This is just to ensure that we have a snapshot and to prevent
759
+ // a theoretically possible NullPointerException.
760
+ continue;
761
+ }
762
+ SharedElement sharedElement =
763
+ new SharedElement(sharedView, sourceViewSnapshot, targetView, new Snapshot(targetView));
764
+ sharedElements.add(sharedElement);
765
+ break;
766
+ }
767
+ }
768
+ if (sharedElements.isEmpty()) {
769
+ return;
770
+ }
771
+ mSharedElements = sharedElements;
772
+ mSharedElementsWithAnimation.clear();
773
+ for (SharedElement sharedElement : sharedElements) {
774
+ mSharedElementsLookup.put(sharedElement.sourceView.getId(), sharedElement);
775
+ mSharedElementsWithAnimation.add(sharedElement);
776
+ }
777
+ setupTransitionContainer();
778
+ reparentSharedViewsForCurrentTransition(sharedElements);
779
+ startSharedTransition(
780
+ mSharedElementsWithAnimation, LayoutAnimations.Types.SHARED_ELEMENT_TRANSITION);
781
+ }
782
+
783
+ private void findSharedViewsForScreen(View view, List<View> sharedViews) {
784
+ view = ScreensHelper.getTopScreenForStack(view);
785
+ if (!(view instanceof ViewGroup)) {
786
+ return;
787
+ }
788
+ ViewGroup viewGroup = (ViewGroup) view;
789
+ if (mAnimationsManager.hasAnimationForTag(
790
+ view.getId(), LayoutAnimations.Types.SHARED_ELEMENT_TRANSITION)) {
791
+ sharedViews.add(view);
792
+ }
793
+ for (int i = 0; i < viewGroup.getChildCount(); i++) {
794
+ View child = viewGroup.getChildAt(i);
795
+ findSharedViewsForScreen(child, sharedViews);
796
+ }
797
+ }
699
798
  }
@@ -6,6 +6,8 @@ import com.facebook.react.uimanager.IllegalViewOperationException;
6
6
  import com.facebook.react.uimanager.NativeViewHierarchyManager;
7
7
  import com.facebook.react.uimanager.ViewManager;
8
8
  import com.swmansion.reanimated.ReactNativeUtils;
9
+ import java.lang.reflect.InvocationTargetException;
10
+ import java.lang.reflect.Method;
9
11
  import java.util.ArrayList;
10
12
  import java.util.Arrays;
11
13
  import java.util.HashMap;
@@ -117,9 +119,43 @@ public class Snapshot {
117
119
  borderRadii = new ReactNativeUtils.BorderRadii(0, 0, 0, 0, 0);
118
120
  }
119
121
 
122
+ private int[] tryGetRealPosition(View view) {
123
+ int[] location = new int[2];
124
+ View currentView = view;
125
+ while (currentView != null) {
126
+ location[0] += currentView.getX();
127
+ location[1] += currentView.getY();
128
+ if (ScreensHelper.isScreen(currentView)
129
+ && ScreensHelper.isScreensCoordinatorLayout(currentView.getParent())) {
130
+ View screen = currentView;
131
+ Class<?> screenClass = screen.getClass();
132
+ try {
133
+ Method getContainer = screenClass.getMethod("getContainer");
134
+ currentView = (View) getContainer.invoke(screen);
135
+ } catch (NoSuchMethodException
136
+ | InvocationTargetException
137
+ | IllegalAccessException ignored) {
138
+ }
139
+ } else if (currentView.getParent() instanceof View) {
140
+ currentView = (View) currentView.getParent();
141
+ } else {
142
+ break;
143
+ }
144
+ }
145
+ return location;
146
+ }
147
+
120
148
  public Snapshot(View view) {
121
149
  int[] location = new int[2];
122
150
  view.getLocationOnScreen(location);
151
+ if (location[0] == 0 && location[1] == 0) {
152
+ /*
153
+ In certain cases, when a view is correctly attached to the screen and has computed
154
+ the correct layout, but is not visible on the screen, `getLocationOnScreen` may return
155
+ incorrect values [0, 0]. This behavior can occur during tab changes in bottom tabs.
156
+ */
157
+ location = tryGetRealPosition(view);
158
+ }
123
159
  originX = location[0];
124
160
  originY = location[1];
125
161
  width = view.getWidth();
@@ -0,0 +1,128 @@
1
+ package com.swmansion.reanimated.layoutReanimation;
2
+
3
+ import android.content.Context;
4
+ import android.util.Log;
5
+ import android.view.View;
6
+ import androidx.annotation.NonNull;
7
+ import androidx.fragment.app.Fragment;
8
+ import androidx.fragment.app.FragmentManager;
9
+ import java.lang.reflect.InvocationTargetException;
10
+ import java.lang.reflect.Method;
11
+ import java.util.ArrayList;
12
+ import java.util.HashSet;
13
+ import java.util.List;
14
+ import java.util.Set;
15
+
16
+ public class TabNavigatorObserver {
17
+ private final Set<Integer> mFragmentsWithListenerRegistry = new HashSet<>();
18
+ private final ReaLayoutAnimator mReaLayoutAnimator;
19
+
20
+ public TabNavigatorObserver(ReaLayoutAnimator reaLayoutAnimator) {
21
+ mReaLayoutAnimator = reaLayoutAnimator;
22
+ }
23
+
24
+ public void handleScreenContainerUpdate(View screen) {
25
+ try {
26
+ Class<?> screenClass = screen.getClass();
27
+ Method getScreenFragment = screenClass.getMethod("getFragment");
28
+ Fragment fragment = (Fragment) getScreenFragment.invoke(screen);
29
+ int fragmentTag = fragment.getId();
30
+ if (!mFragmentsWithListenerRegistry.contains(fragmentTag)) {
31
+ mFragmentsWithListenerRegistry.add(fragmentTag);
32
+ fragment
33
+ .getParentFragmentManager()
34
+ .registerFragmentLifecycleCallbacks(new FragmentLifecycleCallbacks(fragment), true);
35
+ }
36
+ } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
37
+ String message = e.getMessage() != null ? e.getMessage() : "Unable to get screen fragment";
38
+ Log.e("[Reanimated]", message);
39
+ }
40
+ }
41
+
42
+ class FragmentLifecycleCallbacks extends FragmentManager.FragmentLifecycleCallbacks {
43
+ private View firstScreen;
44
+ private Method getScreen;
45
+ private Method getActivityState;
46
+ private final Set<Integer> screenTagsWithListener = new HashSet<>();
47
+ private final List<View> nextTransition = new ArrayList<>();
48
+
49
+ public FragmentLifecycleCallbacks(Fragment fragment) {
50
+ try {
51
+ Class<?> screenFragmentClass = fragment.getClass();
52
+ getScreen = screenFragmentClass.getMethod("getScreen");
53
+ View screen = (View) getScreen.invoke(fragment);
54
+ getActivityState = screen.getClass().getMethod("getActivityState");
55
+ addScreenListener(screen);
56
+ } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
57
+ String message =
58
+ e.getMessage() != null ? e.getMessage() : "Unable to get screen activity state";
59
+ Log.e("[Reanimated]", message);
60
+ }
61
+ }
62
+
63
+ private void addScreenListener(View screen)
64
+ throws InvocationTargetException, IllegalAccessException {
65
+ if (screenTagsWithListener.contains(screen.getId())) {
66
+ return;
67
+ }
68
+ screenTagsWithListener.add(screen.getId());
69
+ screen.addOnAttachStateChangeListener(new OnAttachStateChangeListener());
70
+ screen.addOnLayoutChangeListener(
71
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
72
+ if (nextTransition.isEmpty()) {
73
+ return;
74
+ }
75
+ AnimationsManager animationsManager = mReaLayoutAnimator.getAnimationsManager();
76
+ animationsManager.navigationTabChanged(nextTransition.get(0), nextTransition.get(1));
77
+ nextTransition.clear();
78
+ });
79
+ }
80
+
81
+ public void onFragmentAttached(
82
+ FragmentManager fragmentManager, Fragment fragment, Context context) {
83
+ onFragmentUpdate(fragment, true);
84
+ }
85
+
86
+ public void onFragmentDetached(FragmentManager fragmentManager, Fragment fragment) {
87
+ onFragmentUpdate(fragment, false);
88
+ }
89
+
90
+ private void onFragmentUpdate(Fragment fragment, boolean isAttaching) {
91
+ try {
92
+ View screen = (View) getScreen.invoke(fragment);
93
+ if (getActivityState.invoke(screen) == null) {
94
+ return;
95
+ }
96
+ addScreenListener(screen);
97
+
98
+ if (firstScreen == null) {
99
+ firstScreen = screen;
100
+ return;
101
+ }
102
+
103
+ if (isAttaching) {
104
+ nextTransition.add(firstScreen);
105
+ nextTransition.add(screen);
106
+ } else {
107
+ nextTransition.add(screen);
108
+ nextTransition.add(firstScreen);
109
+ }
110
+ firstScreen = null;
111
+ } catch (IllegalAccessException | InvocationTargetException e) {
112
+ String message = e.getMessage() != null ? e.getMessage() : "Unable to get screen view";
113
+ Log.e("[Reanimated]", message);
114
+ }
115
+ }
116
+ }
117
+
118
+ class OnAttachStateChangeListener implements View.OnAttachStateChangeListener {
119
+ @Override
120
+ public void onViewAttachedToWindow(@NonNull View screen) {}
121
+
122
+ @Override
123
+ public void onViewDetachedFromWindow(@NonNull View screen) {
124
+ AnimationsManager animationsManager = mReaLayoutAnimator.getAnimationsManager();
125
+ animationsManager.visitNativeTreeAndMakeSnapshot(screen);
126
+ }
127
+ }
128
+ }
@@ -135,6 +135,14 @@ public class NativeProxy extends NativeProxyCommon {
135
135
  layoutAnimations.checkDuplicateSharedTag(viewTag, screenTag);
136
136
  }
137
137
  }
138
+
139
+ public int[] getSharedGroup(int viewTag) {
140
+ LayoutAnimations layoutAnimations = weakLayoutAnimations.get();
141
+ if (layoutAnimations != null) {
142
+ return layoutAnimations.getSharedGroup(viewTag);
143
+ }
144
+ return new int[]{};
145
+ }
138
146
  };
139
147
  }
140
148
  }