react-native-reanimated 4.4.1 → 4.4.3
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/reanimated/CSS/interpolation/transforms/TransformOperationInterpolator.cpp +12 -5
- package/Common/cpp/reanimated/CSS/misc/ViewStylesRepository.cpp +63 -36
- package/Common/cpp/reanimated/CSS/misc/ViewStylesRepository.h +6 -8
- package/Common/cpp/reanimated/CSS/svg/values/SVGStrokeDashArray.cpp +5 -0
- package/Common/cpp/reanimated/Fabric/ReanimatedMountHook.cpp +25 -12
- package/Common/cpp/reanimated/Fabric/ReanimatedMountHook.h +3 -0
- package/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.cpp +54 -24
- package/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.h +13 -6
- package/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxyCommon.cpp +6 -2
- package/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxyCommon.h +44 -1
- package/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.cpp +125 -43
- package/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Legacy.cpp +228 -102
- package/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Legacy.h +4 -0
- package/Common/cpp/reanimated/LayoutAnimations/SharedTransitions.cpp +8 -3
- package/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.cpp +7 -21
- package/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.h +0 -16
- package/android/CMakeLists.txt +6 -0
- package/android/build.gradle.kts +21 -1
- package/android/src/main/java/com/swmansion/reanimated/NativeProxy.kt +46 -2
- package/android/src/main/java/com/swmansion/reanimated/keyboard/KeyboardAnimationCallback.kt +8 -1
- package/apple/reanimated/apple/ReanimatedModule.mm +12 -1
- package/compatibility.json +1 -1
- package/lib/module/PropsRegistryGarbageCollector.js +3 -6
- package/lib/module/PropsRegistryGarbageCollector.js.map +1 -1
- package/lib/module/animation/styleAnimation.js +4 -3
- package/lib/module/animation/styleAnimation.js.map +1 -1
- package/lib/module/common/constants/platform.js +4 -4
- package/lib/module/common/constants/platform.js.map +1 -1
- package/lib/module/createAnimatedComponent/AnimatedComponent.js +1 -1
- package/lib/module/createAnimatedComponent/AnimatedComponent.js.map +1 -1
- package/lib/module/createAnimatedComponent/getViewInfo.js +3 -1
- package/lib/module/createAnimatedComponent/getViewInfo.js.map +1 -1
- package/lib/module/css/component/AnimatedComponent.js +0 -2
- package/lib/module/css/component/AnimatedComponent.js.map +1 -1
- package/lib/module/css/native/managers/CSSManager.js +5 -5
- package/lib/module/css/native/managers/CSSManager.js.map +1 -1
- package/lib/module/css/native/managers/CSSTransitionsManager.js +8 -1
- package/lib/module/css/native/managers/CSSTransitionsManager.js.map +1 -1
- package/lib/module/css/svg/native/processors/stroke.js +9 -5
- package/lib/module/css/svg/native/processors/stroke.js.map +1 -1
- package/lib/module/layoutReanimation/animationBuilder/ComplexAnimationBuilder.js +6 -3
- package/lib/module/layoutReanimation/animationBuilder/ComplexAnimationBuilder.js.map +1 -1
- package/lib/module/layoutReanimation/animationsManager.js +39 -11
- package/lib/module/layoutReanimation/animationsManager.js.map +1 -1
- package/lib/module/mappers.js +1 -1
- package/lib/module/mappers.js.map +1 -1
- package/lib/module/platform-specific/findHostInstance.js +8 -5
- package/lib/module/platform-specific/findHostInstance.js.map +1 -1
- package/lib/module/platform-specific/jsVersion.js +1 -1
- package/lib/module/updateProps/updateProps.js +3 -2
- package/lib/module/updateProps/updateProps.js.map +1 -1
- package/lib/module/valueSetter.js +6 -7
- package/lib/module/valueSetter.js.map +1 -1
- package/lib/typescript/PropsRegistryGarbageCollector.d.ts +0 -1
- package/lib/typescript/PropsRegistryGarbageCollector.d.ts.map +1 -1
- package/lib/typescript/animation/styleAnimation.d.ts +1 -1
- package/lib/typescript/animation/styleAnimation.d.ts.map +1 -1
- package/lib/typescript/common/constants/platform.d.ts.map +1 -1
- package/lib/typescript/createAnimatedComponent/AnimatedComponent.d.ts.map +1 -1
- package/lib/typescript/createAnimatedComponent/commonTypes.d.ts +0 -1
- package/lib/typescript/createAnimatedComponent/commonTypes.d.ts.map +1 -1
- package/lib/typescript/createAnimatedComponent/getViewInfo.d.ts.map +1 -1
- package/lib/typescript/css/component/AnimatedComponent.d.ts +0 -1
- package/lib/typescript/css/component/AnimatedComponent.d.ts.map +1 -1
- package/lib/typescript/css/native/managers/CSSTransitionsManager.d.ts +5 -1
- package/lib/typescript/css/native/managers/CSSTransitionsManager.d.ts.map +1 -1
- package/lib/typescript/css/svg/native/processors/stroke.d.ts.map +1 -1
- package/lib/typescript/layoutReanimation/animationBuilder/ComplexAnimationBuilder.d.ts +17 -14
- package/lib/typescript/layoutReanimation/animationBuilder/ComplexAnimationBuilder.d.ts.map +1 -1
- package/lib/typescript/layoutReanimation/animationsManager.d.ts.map +1 -1
- package/lib/typescript/platform-specific/findHostInstance.d.ts.map +1 -1
- package/lib/typescript/platform-specific/jsVersion.d.ts +1 -1
- package/lib/typescript/platform-specific/types.d.ts +1 -0
- package/lib/typescript/platform-specific/types.d.ts.map +1 -1
- package/lib/typescript/updateProps/updateProps.d.ts.map +1 -1
- package/package.json +3 -3
- package/scripts/reanimated_utils.rb +7 -0
- package/src/PropsRegistryGarbageCollector.ts +3 -6
- package/src/animation/styleAnimation.ts +5 -3
- package/src/common/constants/platform.ts +4 -4
- package/src/createAnimatedComponent/AnimatedComponent.tsx +3 -1
- package/src/createAnimatedComponent/commonTypes.ts +0 -1
- package/src/createAnimatedComponent/getViewInfo.ts +3 -1
- package/src/css/component/AnimatedComponent.tsx +0 -2
- package/src/css/native/managers/CSSManager.ts +8 -8
- package/src/css/native/managers/CSSTransitionsManager.ts +9 -2
- package/src/css/svg/native/processors/stroke.ts +9 -6
- package/src/layoutReanimation/animationBuilder/ComplexAnimationBuilder.ts +39 -36
- package/src/layoutReanimation/animationsManager.ts +41 -11
- package/src/mappers.ts +1 -1
- package/src/platform-specific/findHostInstance.ts +7 -7
- package/src/platform-specific/jsVersion.ts +1 -1
- package/src/platform-specific/types.ts +2 -0
- package/src/updateProps/updateProps.ts +3 -2
- package/src/valueSetter.ts +7 -7
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#include <reanimated/LayoutAnimations/LayoutAnimationsProxy_Legacy.h>
|
|
2
2
|
|
|
3
|
+
#include <react/debug/react_native_assert.h>
|
|
3
4
|
#include <react/renderer/mounting/ShadowViewMutation.h>
|
|
4
5
|
|
|
5
6
|
#include <memory>
|
|
@@ -37,17 +38,25 @@ std::optional<MountingTransaction> LayoutAnimationsProxy_Legacy::pullTransaction
|
|
|
37
38
|
std::vector<std::shared_ptr<MutationNode>> roots;
|
|
38
39
|
std::unordered_map<Tag, Tag> movedViews;
|
|
39
40
|
|
|
41
|
+
reconcileContradictedRemovals(mutations, filteredMutations, surfaceId);
|
|
42
|
+
|
|
40
43
|
addOngoingAnimations(surfaceId, filteredMutations);
|
|
41
44
|
|
|
42
45
|
#ifdef ANDROID
|
|
43
46
|
restoreOpacityInCaseOfFlakyEnteringAnimation(surfaceId);
|
|
44
47
|
#endif // ANDROID
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
layoutAnimations_.
|
|
48
|
+
auto &updateMap = surfaceManager.getUpdateMap(surfaceId);
|
|
49
|
+
for (const auto tag : maybeSettledAnimationTags_) {
|
|
50
|
+
const auto layoutAnimationIt = layoutAnimations_.find(tag);
|
|
51
|
+
if (layoutAnimationIt == layoutAnimations_.end() || !layoutAnimationIt->second.isSettled()) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
layoutAnimations_.erase(layoutAnimationIt);
|
|
48
55
|
updateMap.erase(tag);
|
|
49
56
|
}
|
|
50
|
-
|
|
57
|
+
maybeSettledAnimationTags_.clear();
|
|
58
|
+
// Past this point no animation can be settled - we hold the mutex for the whole
|
|
59
|
+
// transaction, so no end callback can run until we return.
|
|
51
60
|
|
|
52
61
|
parseRemoveMutations(movedViews, mutations, roots);
|
|
53
62
|
|
|
@@ -62,6 +71,40 @@ std::optional<MountingTransaction> LayoutAnimationsProxy_Legacy::pullTransaction
|
|
|
62
71
|
return MountingTransaction{surfaceId, transactionNumber, std::move(filteredMutations), telemetry};
|
|
63
72
|
}
|
|
64
73
|
|
|
74
|
+
// If React re-creates or re-inserts a tag whose exiting removal we are still
|
|
75
|
+
// withholding, it has contradicted that withheld Remove/Delete. Flush it now
|
|
76
|
+
// instead of letting it fire later against a stale hierarchy (which would
|
|
77
|
+
// unmount the wrong, still-live view and crash the mounting layer).
|
|
78
|
+
//
|
|
79
|
+
// This must run before addOngoingAnimations (which would otherwise emit an
|
|
80
|
+
// Update for a tag we are about to Delete this frame) and before
|
|
81
|
+
// parseRemoveMutations, so the rest of the pipeline sees clean bookkeeping.
|
|
82
|
+
void LayoutAnimationsProxy_Legacy::reconcileContradictedRemovals(
|
|
83
|
+
ShadowViewMutationList &mutations,
|
|
84
|
+
ShadowViewMutationList &filteredMutations,
|
|
85
|
+
SurfaceId surfaceId) const {
|
|
86
|
+
auto &[deadNodes] = surfaceContext_[surfaceId];
|
|
87
|
+
for (auto &mutation : mutations) {
|
|
88
|
+
if (mutation.type != ShadowViewMutation::Type::Create && mutation.type != ShadowViewMutation::Type::Insert) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
auto tag = mutation.newChildShadowView.tag;
|
|
92
|
+
auto it = nodeForTag_.find(tag);
|
|
93
|
+
// Only a MutationNode represents a withheld removal; a plain Node is just a
|
|
94
|
+
// live parent of some removed child and must be left untouched.
|
|
95
|
+
if (it == nodeForTag_.end() || !it->second->isMutationNode()) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
auto node = std::static_pointer_cast<MutationNode>(it->second);
|
|
99
|
+
// Flush the withheld Remove/Delete for this tag (and its withheld subtree)
|
|
100
|
+
// right now, mirroring the deadNodes cleanup in handleRemovals. This removes
|
|
101
|
+
// the stale view before React's Create/Insert re-registers the same tag.
|
|
102
|
+
endAnimationsRecursively(node, filteredMutations);
|
|
103
|
+
maybeDropAncestors(node->unflattenedParent, node, filteredMutations);
|
|
104
|
+
deadNodes.erase(node);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
65
108
|
std::optional<SurfaceId> LayoutAnimationsProxy_Legacy::progressLayoutAnimation(int tag, const jsi::Object &newStyle) {
|
|
66
109
|
#ifdef LAYOUT_ANIMATIONS_LOGS
|
|
67
110
|
LOG(INFO) << "progress layout animation for tag " << tag << std::endl;
|
|
@@ -109,11 +152,10 @@ std::optional<SurfaceId> LayoutAnimationsProxy_Legacy::endLayoutAnimation(int ta
|
|
|
109
152
|
// one after the other, so we need to keep count of how many
|
|
110
153
|
// were actually triggered, so that we don't cleanup necessary
|
|
111
154
|
// structures too early
|
|
112
|
-
if (layoutAnimation.count >
|
|
113
|
-
layoutAnimation.count--;
|
|
155
|
+
if (--layoutAnimation.count > 0) {
|
|
114
156
|
return {};
|
|
115
157
|
}
|
|
116
|
-
|
|
158
|
+
maybeSettledAnimationTags_.insert(tag);
|
|
117
159
|
auto surfaceId = layoutAnimation.finalView.surfaceId;
|
|
118
160
|
|
|
119
161
|
if (!shouldRemove || !nodeForTag_.contains(tag)) {
|
|
@@ -121,6 +163,10 @@ std::optional<SurfaceId> LayoutAnimationsProxy_Legacy::endLayoutAnimation(int ta
|
|
|
121
163
|
}
|
|
122
164
|
|
|
123
165
|
auto node = nodeForTag_[tag];
|
|
166
|
+
if (!node->isMutationNode()) {
|
|
167
|
+
react_native_assert(false && "exiting tag must map to a MutationNode");
|
|
168
|
+
return {};
|
|
169
|
+
}
|
|
124
170
|
auto mutationNode = std::static_pointer_cast<MutationNode>(node);
|
|
125
171
|
mutationNode->state = ExitingState_Legacy::DEAD;
|
|
126
172
|
auto &[deadNodes] = surfaceContext_[surfaceId];
|
|
@@ -406,7 +452,13 @@ void LayoutAnimationsProxy_Legacy::addOngoingAnimations(SurfaceId surfaceId, Sha
|
|
|
406
452
|
|
|
407
453
|
auto layoutAnimationIt = layoutAnimations_.find(tag);
|
|
408
454
|
|
|
409
|
-
if (layoutAnimationIt == layoutAnimations_.end()
|
|
455
|
+
if (layoutAnimationIt == layoutAnimations_.end() ||
|
|
456
|
+
// A settled animation is normally cleaned up without applying further
|
|
457
|
+
// updates. The exception is a flaky entering animation whose opacity was
|
|
458
|
+
// never restored (the view wasn't mounted in time) - we still need to
|
|
459
|
+
// apply that pending opacity, otherwise the view stays invisible. Only
|
|
460
|
+
// entering animations carry an opacity value.
|
|
461
|
+
(layoutAnimationIt->second.isSettled() && !layoutAnimationIt->second.opacity.has_value())) {
|
|
410
462
|
continue;
|
|
411
463
|
}
|
|
412
464
|
|
|
@@ -633,38 +685,60 @@ void LayoutAnimationsProxy_Legacy::startEnteringAnimation(const int tag, ShadowV
|
|
|
633
685
|
|
|
634
686
|
auto &viewProps = static_cast<const ViewProps &>(*mutation.newChildShadowView.props);
|
|
635
687
|
auto opacity = viewProps.opacity;
|
|
688
|
+
#ifdef ANDROID
|
|
689
|
+
const auto handle = pendingStarts_[tag].handle;
|
|
690
|
+
pendingStarts_[tag].count++;
|
|
691
|
+
#endif
|
|
636
692
|
|
|
637
|
-
scheduleOnUI(
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
693
|
+
scheduleOnUI(
|
|
694
|
+
uiScheduler_,
|
|
695
|
+
[weakThis = weak_from_this(),
|
|
696
|
+
finalView,
|
|
697
|
+
current,
|
|
698
|
+
mutation,
|
|
699
|
+
opacity,
|
|
700
|
+
tag
|
|
701
|
+
#ifdef ANDROID
|
|
702
|
+
,
|
|
703
|
+
handle
|
|
704
|
+
#endif
|
|
705
|
+
]() {
|
|
706
|
+
auto strongThis = weakThis.lock();
|
|
707
|
+
if (!strongThis) {
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
642
710
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
tag,
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
711
|
+
Rect window{};
|
|
712
|
+
{
|
|
713
|
+
auto &mutex = strongThis->mutex;
|
|
714
|
+
auto lock = std::unique_lock<std::recursive_mutex>(mutex);
|
|
715
|
+
#ifdef ANDROID
|
|
716
|
+
if (consumeIsCancelled(strongThis->pendingStarts_, tag, handle)) {
|
|
717
|
+
// the view was removed before this start could run
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
#endif
|
|
721
|
+
strongThis->layoutAnimations_.insert_or_assign(
|
|
722
|
+
tag,
|
|
723
|
+
LayoutAnimation{
|
|
724
|
+
.finalView = finalView, .currentView = current, .parentTag = mutation.parentTag, .opacity = opacity});
|
|
725
|
+
window = strongThis->surfaceManager.getWindow(mutation.newChildShadowView.surfaceId);
|
|
726
|
+
}
|
|
653
727
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
728
|
+
Snapshot values(mutation.newChildShadowView, window);
|
|
729
|
+
auto &uiRuntime = strongThis->uiRuntime_;
|
|
730
|
+
jsi::Object yogaValues(uiRuntime);
|
|
731
|
+
yogaValues.setProperty(uiRuntime, "targetOriginX", values.x);
|
|
732
|
+
yogaValues.setProperty(uiRuntime, "targetGlobalOriginX", values.x);
|
|
733
|
+
yogaValues.setProperty(uiRuntime, "targetOriginY", values.y);
|
|
734
|
+
yogaValues.setProperty(uiRuntime, "targetGlobalOriginY", values.y);
|
|
735
|
+
yogaValues.setProperty(uiRuntime, "targetWidth", values.width);
|
|
736
|
+
yogaValues.setProperty(uiRuntime, "targetHeight", values.height);
|
|
737
|
+
yogaValues.setProperty(uiRuntime, "windowWidth", values.windowWidth);
|
|
738
|
+
yogaValues.setProperty(uiRuntime, "windowHeight", values.windowHeight);
|
|
739
|
+
strongThis->layoutAnimationsManager_->startLayoutAnimation(
|
|
740
|
+
uiRuntime, tag, LayoutAnimationType::ENTERING, yogaValues);
|
|
741
|
+
});
|
|
668
742
|
}
|
|
669
743
|
|
|
670
744
|
void LayoutAnimationsProxy_Legacy::startExitingAnimation(const int tag, ShadowViewMutation &mutation) const {
|
|
@@ -672,38 +746,62 @@ void LayoutAnimationsProxy_Legacy::startExitingAnimation(const int tag, ShadowVi
|
|
|
672
746
|
LOG(INFO) << "start exiting animation for tag " << tag << std::endl;
|
|
673
747
|
#endif
|
|
674
748
|
auto surfaceId = mutation.oldChildShadowView.surfaceId;
|
|
749
|
+
#ifdef ANDROID
|
|
750
|
+
const auto handle = pendingStarts_[tag].handle;
|
|
751
|
+
pendingStarts_[tag].count++;
|
|
752
|
+
#endif
|
|
675
753
|
|
|
676
|
-
scheduleOnUI(
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
754
|
+
scheduleOnUI(
|
|
755
|
+
uiScheduler_,
|
|
756
|
+
[weakThis = weak_from_this(),
|
|
757
|
+
tag,
|
|
758
|
+
mutation,
|
|
759
|
+
surfaceId
|
|
760
|
+
#ifdef ANDROID
|
|
761
|
+
,
|
|
762
|
+
handle
|
|
763
|
+
#endif
|
|
764
|
+
]() {
|
|
765
|
+
auto strongThis = weakThis.lock();
|
|
766
|
+
if (!strongThis) {
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
690
769
|
|
|
691
|
-
|
|
770
|
+
auto oldView = mutation.oldChildShadowView;
|
|
771
|
+
Rect window{};
|
|
772
|
+
{
|
|
773
|
+
auto &mutex = strongThis->mutex;
|
|
774
|
+
auto lock = std::unique_lock<std::recursive_mutex>(mutex);
|
|
775
|
+
#ifdef ANDROID
|
|
776
|
+
if (consumeIsCancelled(strongThis->pendingStarts_, tag, handle)) {
|
|
777
|
+
// the view was removed (e.g. its subtree was force-ended by a screen
|
|
778
|
+
// pop) before this start could run — its Remove+Delete are already on
|
|
779
|
+
// their way to the mounting layer, so starting the animation now
|
|
780
|
+
// would emit updates for a view that's about to be deleted
|
|
781
|
+
strongThis->layoutAnimationsManager_->clearLayoutAnimationConfig(tag);
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
#endif
|
|
785
|
+
strongThis->createLayoutAnimation(mutation, oldView, surfaceId, tag);
|
|
786
|
+
window = strongThis->surfaceManager.getWindow(surfaceId);
|
|
787
|
+
}
|
|
692
788
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
uiRuntime,
|
|
705
|
-
|
|
706
|
-
|
|
789
|
+
Snapshot values(oldView, window);
|
|
790
|
+
|
|
791
|
+
auto &uiRuntime = strongThis->uiRuntime_;
|
|
792
|
+
jsi::Object yogaValues(uiRuntime);
|
|
793
|
+
yogaValues.setProperty(uiRuntime, "currentOriginX", values.x);
|
|
794
|
+
yogaValues.setProperty(uiRuntime, "currentGlobalOriginX", values.x);
|
|
795
|
+
yogaValues.setProperty(uiRuntime, "currentOriginY", values.y);
|
|
796
|
+
yogaValues.setProperty(uiRuntime, "currentGlobalOriginY", values.y);
|
|
797
|
+
yogaValues.setProperty(uiRuntime, "currentWidth", values.width);
|
|
798
|
+
yogaValues.setProperty(uiRuntime, "currentHeight", values.height);
|
|
799
|
+
yogaValues.setProperty(uiRuntime, "windowWidth", values.windowWidth);
|
|
800
|
+
yogaValues.setProperty(uiRuntime, "windowHeight", values.windowHeight);
|
|
801
|
+
strongThis->layoutAnimationsManager_->startLayoutAnimation(
|
|
802
|
+
uiRuntime, tag, LayoutAnimationType::EXITING, yogaValues);
|
|
803
|
+
strongThis->layoutAnimationsManager_->clearLayoutAnimationConfig(tag);
|
|
804
|
+
});
|
|
707
805
|
}
|
|
708
806
|
|
|
709
807
|
void LayoutAnimationsProxy_Legacy::startLayoutAnimation(const int tag, const ShadowViewMutation &mutation) const {
|
|
@@ -711,43 +809,64 @@ void LayoutAnimationsProxy_Legacy::startLayoutAnimation(const int tag, const Sha
|
|
|
711
809
|
LOG(INFO) << "start layout animation for tag " << tag << std::endl;
|
|
712
810
|
#endif
|
|
713
811
|
auto surfaceId = mutation.oldChildShadowView.surfaceId;
|
|
812
|
+
#ifdef ANDROID
|
|
813
|
+
const auto handle = pendingStarts_[tag].handle;
|
|
814
|
+
pendingStarts_[tag].count++;
|
|
815
|
+
#endif
|
|
714
816
|
|
|
715
|
-
scheduleOnUI(
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
817
|
+
scheduleOnUI(
|
|
818
|
+
uiScheduler_,
|
|
819
|
+
[weakThis = weak_from_this(),
|
|
820
|
+
mutation,
|
|
821
|
+
surfaceId,
|
|
822
|
+
tag
|
|
823
|
+
#ifdef ANDROID
|
|
824
|
+
,
|
|
825
|
+
handle
|
|
826
|
+
#endif
|
|
827
|
+
]() {
|
|
828
|
+
auto strongThis = weakThis.lock();
|
|
829
|
+
if (!strongThis) {
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
729
832
|
|
|
730
|
-
|
|
731
|
-
|
|
833
|
+
auto oldView = mutation.oldChildShadowView;
|
|
834
|
+
Rect window{};
|
|
835
|
+
{
|
|
836
|
+
auto &mutex = strongThis->mutex;
|
|
837
|
+
auto lock = std::unique_lock<std::recursive_mutex>(mutex);
|
|
838
|
+
#ifdef ANDROID
|
|
839
|
+
if (consumeIsCancelled(strongThis->pendingStarts_, tag, handle)) {
|
|
840
|
+
// the view was removed before this start could run
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
843
|
+
#endif
|
|
844
|
+
strongThis->createLayoutAnimation(mutation, oldView, surfaceId, tag);
|
|
845
|
+
window = strongThis->surfaceManager.getWindow(surfaceId);
|
|
846
|
+
}
|
|
732
847
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
848
|
+
Snapshot currentValues(oldView, window);
|
|
849
|
+
Snapshot targetValues(mutation.newChildShadowView, window);
|
|
850
|
+
|
|
851
|
+
auto &uiRuntime = strongThis->uiRuntime_;
|
|
852
|
+
jsi::Object yogaValues(uiRuntime);
|
|
853
|
+
yogaValues.setProperty(uiRuntime, "currentOriginX", currentValues.x);
|
|
854
|
+
yogaValues.setProperty(uiRuntime, "currentGlobalOriginX", currentValues.x);
|
|
855
|
+
yogaValues.setProperty(uiRuntime, "currentOriginY", currentValues.y);
|
|
856
|
+
yogaValues.setProperty(uiRuntime, "currentGlobalOriginY", currentValues.y);
|
|
857
|
+
yogaValues.setProperty(uiRuntime, "currentWidth", currentValues.width);
|
|
858
|
+
yogaValues.setProperty(uiRuntime, "currentHeight", currentValues.height);
|
|
859
|
+
yogaValues.setProperty(uiRuntime, "targetOriginX", targetValues.x);
|
|
860
|
+
yogaValues.setProperty(uiRuntime, "targetGlobalOriginX", targetValues.x);
|
|
861
|
+
yogaValues.setProperty(uiRuntime, "targetOriginY", targetValues.y);
|
|
862
|
+
yogaValues.setProperty(uiRuntime, "targetGlobalOriginY", targetValues.y);
|
|
863
|
+
yogaValues.setProperty(uiRuntime, "targetWidth", targetValues.width);
|
|
864
|
+
yogaValues.setProperty(uiRuntime, "targetHeight", targetValues.height);
|
|
865
|
+
yogaValues.setProperty(uiRuntime, "windowWidth", targetValues.windowWidth);
|
|
866
|
+
yogaValues.setProperty(uiRuntime, "windowHeight", targetValues.windowHeight);
|
|
867
|
+
strongThis->layoutAnimationsManager_->startLayoutAnimation(
|
|
868
|
+
uiRuntime, tag, LayoutAnimationType::LAYOUT, yogaValues);
|
|
869
|
+
});
|
|
751
870
|
}
|
|
752
871
|
|
|
753
872
|
void LayoutAnimationsProxy_Legacy::updateOngoingAnimationTarget(const int tag, const ShadowViewMutation &mutation)
|
|
@@ -757,10 +876,17 @@ void LayoutAnimationsProxy_Legacy::updateOngoingAnimationTarget(const int tag, c
|
|
|
757
876
|
}
|
|
758
877
|
|
|
759
878
|
void LayoutAnimationsProxy_Legacy::maybeCancelAnimation(const int tag) const {
|
|
760
|
-
|
|
879
|
+
#ifdef ANDROID
|
|
880
|
+
// invalidate animation starts that are scheduled but haven't run yet
|
|
881
|
+
if (const auto it = pendingStarts_.find(tag); it != pendingStarts_.end()) {
|
|
882
|
+
it->second.handle++;
|
|
883
|
+
}
|
|
884
|
+
#endif
|
|
885
|
+
const auto layoutAnimationIt = layoutAnimations_.find(tag);
|
|
886
|
+
if (layoutAnimationIt == layoutAnimations_.end()) {
|
|
761
887
|
return;
|
|
762
888
|
}
|
|
763
|
-
layoutAnimations_.erase(
|
|
889
|
+
layoutAnimations_.erase(layoutAnimationIt);
|
|
764
890
|
scheduleOnUI(uiScheduler_, [weakThis = weak_from_this(), tag]() {
|
|
765
891
|
auto strongThis = weakThis.lock();
|
|
766
892
|
if (!strongThis) {
|
|
@@ -148,6 +148,10 @@ struct LayoutAnimationsProxy_Legacy : public LayoutAnimationsProxyCommon,
|
|
|
148
148
|
std::optional<SurfaceId> endLayoutAnimation(int tag, bool shouldRemove) override;
|
|
149
149
|
void maybeCancelAnimation(const int tag) const;
|
|
150
150
|
|
|
151
|
+
void reconcileContradictedRemovals(
|
|
152
|
+
ShadowViewMutationList &mutations,
|
|
153
|
+
ShadowViewMutationList &filteredMutations,
|
|
154
|
+
SurfaceId surfaceId) const;
|
|
151
155
|
void parseRemoveMutations(
|
|
152
156
|
std::unordered_map<Tag, Tag> &movedViews,
|
|
153
157
|
ShadowViewMutationList &mutations,
|
|
@@ -210,7 +210,11 @@ Tag LayoutAnimationsProxy_Experimental::getOrCreateContainer(
|
|
|
210
210
|
ShadowViewMutationList &filteredMutations,
|
|
211
211
|
SurfaceId surfaceId) const {
|
|
212
212
|
auto containerTag = sharedTransitionManager_->containerTags_[sharedTag];
|
|
213
|
-
auto shouldCreateContainer =
|
|
213
|
+
auto shouldCreateContainer = true;
|
|
214
|
+
if (containerTag != -1) {
|
|
215
|
+
const auto layoutAnimationIt = layoutAnimations_.find(containerTag);
|
|
216
|
+
shouldCreateContainer = layoutAnimationIt == layoutAnimations_.end() || layoutAnimationIt->second.isSettled();
|
|
217
|
+
}
|
|
214
218
|
|
|
215
219
|
if (shouldCreateContainer) {
|
|
216
220
|
containerTag = containerTag_;
|
|
@@ -264,11 +268,12 @@ void LayoutAnimationsProxy_Experimental::handleSharedTransitionsStart(
|
|
|
264
268
|
auto &[_, after] = transition.snapshot;
|
|
265
269
|
|
|
266
270
|
auto containerTag = sharedTransitionManager_->containerTags_[sharedTag];
|
|
267
|
-
|
|
271
|
+
const auto layoutAnimationIt = layoutAnimations_.find(containerTag);
|
|
272
|
+
if (layoutAnimationIt == layoutAnimations_.end() || layoutAnimationIt->second.isSettled()) {
|
|
268
273
|
continue;
|
|
269
274
|
}
|
|
270
275
|
after.tag = containerTag;
|
|
271
|
-
const auto &la =
|
|
276
|
+
const auto &la = layoutAnimationIt->second;
|
|
272
277
|
if (la.finalView.layoutMetrics != after.layoutMetrics) {
|
|
273
278
|
overrideTransform(after, transition.transform[AFTER], propsParserContext);
|
|
274
279
|
startSharedTransition(containerTag, la.currentView, after, surfaceId);
|
|
@@ -322,9 +322,9 @@ void ReanimatedModuleProxy::init(const PlatformDepMethodsHolder &platformDepMeth
|
|
|
322
322
|
if (!surfaceId) {
|
|
323
323
|
return;
|
|
324
324
|
}
|
|
325
|
+
// The flush set is drained by `executeLayoutAnimationsRequests`, driven
|
|
326
|
+
// by `runGrandCallback` (backend) or a JS `requestAnimationFrameFinalizer` (non-backend).
|
|
325
327
|
strongThis->layoutAnimationFlushRequests_.insert(*surfaceId);
|
|
326
|
-
|
|
327
|
-
strongThis->requestRenderForLayoutAnimations();
|
|
328
328
|
};
|
|
329
329
|
|
|
330
330
|
EndLayoutAnimationFunction endLayoutAnimation = [weakThis = weak_from_this()](int tag, bool shouldRemove) {
|
|
@@ -335,14 +335,6 @@ void ReanimatedModuleProxy::init(const PlatformDepMethodsHolder &platformDepMeth
|
|
|
335
335
|
}
|
|
336
336
|
|
|
337
337
|
auto surfaceId = strongThis->layoutAnimationsProxy_->endLayoutAnimation(tag, shouldRemove);
|
|
338
|
-
|
|
339
|
-
if constexpr (StaticFeatureFlags::getFlag("USE_ANIMATION_BACKEND")) {
|
|
340
|
-
// in the backend path this is called from runGrandCallback,
|
|
341
|
-
// we are guaranteed to have the changes flushed
|
|
342
|
-
} else {
|
|
343
|
-
strongThis->requestRenderForLayoutAnimations();
|
|
344
|
-
}
|
|
345
|
-
|
|
346
338
|
if (!surfaceId) {
|
|
347
339
|
return;
|
|
348
340
|
}
|
|
@@ -649,16 +641,14 @@ jsi::Value ReanimatedModuleProxy::getSettledUpdates(jsi::Runtime &rt) {
|
|
|
649
641
|
StaticFeatureFlags::getFlag("FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS") &&
|
|
650
642
|
"getSettledUpdates requires FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS static feature flag to be enabled");
|
|
651
643
|
|
|
644
|
+
constexpr double SETTLED_ANIMATION_THRESHOLD_MS = 1000;
|
|
645
|
+
|
|
652
646
|
// TODO(future): use unified timestamp
|
|
653
647
|
const auto currentTimestamp = getAnimationTimestamp_();
|
|
654
648
|
|
|
655
|
-
// TODO: fix bug when threshold difference is smaller than 1 second
|
|
656
649
|
// TODO(future): flush updates from CSS animations and CSS transitions registries
|
|
657
|
-
// TODO(future): find a better way to obtain timestamp for removing updates
|
|
658
|
-
// TODO(future): move removing old updates to separate method
|
|
659
650
|
auto lock = updatesRegistryManager_->lock();
|
|
660
|
-
return animatedPropsRegistry_->
|
|
661
|
-
rt, currentTimestamp - 1000 /* 1 second */, currentTimestamp - 2000 /* 2 seconds */);
|
|
651
|
+
return animatedPropsRegistry_->collectSettledUpdates(rt, currentTimestamp - SETTLED_ANIMATION_THRESHOLD_MS);
|
|
662
652
|
}
|
|
663
653
|
|
|
664
654
|
bool ReanimatedModuleProxy::handleEvent(
|
|
@@ -808,11 +798,6 @@ void ReanimatedModuleProxy::performOperations() {
|
|
|
808
798
|
}
|
|
809
799
|
|
|
810
800
|
commitUpdates(uiRuntime, updatesBatch);
|
|
811
|
-
|
|
812
|
-
// Clear the entire cache after the commit
|
|
813
|
-
// (we don't know if the view is updated from outside of Reanimated
|
|
814
|
-
// so we have to clear the entire cache)
|
|
815
|
-
viewStylesRepository_->clearNodesCache();
|
|
816
801
|
}
|
|
817
802
|
|
|
818
803
|
void ReanimatedModuleProxy::performNonLayoutOperations() {
|
|
@@ -1206,7 +1191,8 @@ void ReanimatedModuleProxy::initializeFabric(const std::shared_ptr<UIManager> &u
|
|
|
1206
1191
|
// TODO: we don't use the mount hook here, but we still need a way to handleNodeRemovals
|
|
1207
1192
|
// for now we leave this to leak the memory, a fix will come in a follow-up
|
|
1208
1193
|
} else {
|
|
1209
|
-
mountHook_ =
|
|
1194
|
+
mountHook_ =
|
|
1195
|
+
std::make_shared<ReanimatedMountHook>(uiManager_, updatesRegistryManager_, viewStylesRepository_, request);
|
|
1210
1196
|
}
|
|
1211
1197
|
|
|
1212
1198
|
commitHook_ = std::make_shared<ReanimatedCommitHook>(uiManager_, updatesRegistryManager_, layoutAnimationsProxy_);
|
|
@@ -201,20 +201,6 @@ class ReanimatedModuleProxy : public std::enable_shared_from_this<ReanimatedModu
|
|
|
201
201
|
void commitUpdates(jsi::Runtime &rt, const UpdatesBatch &updatesBatch);
|
|
202
202
|
void applySynchronousUpdates(UpdatesBatch &updatesBatch, bool allowPartialUpdates);
|
|
203
203
|
|
|
204
|
-
/** Use only on the UI thread. */
|
|
205
|
-
void requestRenderForLayoutAnimations() {
|
|
206
|
-
if (layoutAnimationRenderRequested_) [[likely]] {
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
layoutAnimationRenderRequested_ = true;
|
|
211
|
-
requestRender_([weakThis = weak_from_this()](double) {
|
|
212
|
-
if (auto strongThis = weakThis.lock()) {
|
|
213
|
-
strongThis->layoutAnimationRenderRequested_ = false;
|
|
214
|
-
}
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
|
|
218
204
|
#if REACT_NATIVE_VERSION_MINOR >= 85
|
|
219
205
|
std::shared_ptr<UIManagerAnimationBackend> getAnimationBackend();
|
|
220
206
|
AnimationMutations runGrandCallback(AnimationTimestamp timestamp, GrandCallbackSource source);
|
|
@@ -279,8 +265,6 @@ class ReanimatedModuleProxy : public std::enable_shared_from_this<ReanimatedModu
|
|
|
279
265
|
std::shared_ptr<ReanimatedMountHook> mountHook_;
|
|
280
266
|
/// Access only on UI thread.
|
|
281
267
|
std::set<SurfaceId> layoutAnimationFlushRequests_;
|
|
282
|
-
/// Access only on UI thread.
|
|
283
|
-
bool layoutAnimationRenderRequested_;
|
|
284
268
|
|
|
285
269
|
const KeyboardEventSubscribeFunction subscribeForKeyboardEventsFunction_;
|
|
286
270
|
const KeyboardEventUnsubscribeFunction unsubscribeFromKeyboardEventsFunction_;
|
package/android/CMakeLists.txt
CHANGED
|
@@ -49,6 +49,12 @@ add_library(reanimated SHARED ${REANIMATED_COMMON_CPP_SOURCES}
|
|
|
49
49
|
target_precompile_headers(reanimated PRIVATE
|
|
50
50
|
"${ANDROID_CPP_DIR}/ReanimatedPCH.h")
|
|
51
51
|
|
|
52
|
+
# Stop Clang from embedding a build timestamp in the .pch. Without this the PCH
|
|
53
|
+
# is non-reproducible across builds, so ccache can't reuse it and translation
|
|
54
|
+
# units reject a restored PCH as "modified since built".
|
|
55
|
+
target_compile_options(reanimated PRIVATE
|
|
56
|
+
"$<$<COMPILE_LANGUAGE:CXX>:-Xclang;-fno-pch-timestamp>")
|
|
57
|
+
|
|
52
58
|
if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 80)
|
|
53
59
|
include(
|
|
54
60
|
"${REACT_NATIVE_DIR}/ReactCommon/cmake-utils/react-native-flags.cmake")
|
package/android/build.gradle.kts
CHANGED
|
@@ -100,6 +100,15 @@ fun validateConflictingFeatureFlags(featureFlags: HashMap<String, String>) {
|
|
|
100
100
|
"[Reanimated] The feature flags `ANDROID_SYNCHRONOUSLY_UPDATE_UI_PROPS` and `ENABLE_SHARED_ELEMENT_TRANSITIONS` cannot be enabled simultaneously. Please disable one of them in your package.json."
|
|
101
101
|
)
|
|
102
102
|
}
|
|
103
|
+
|
|
104
|
+
val useAnimationBackend = featureFlags["USE_ANIMATION_BACKEND"] == "true"
|
|
105
|
+
val forceReactRenderForSettledAnimations = featureFlags["FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS"] == "true"
|
|
106
|
+
|
|
107
|
+
if (useAnimationBackend && forceReactRenderForSettledAnimations) {
|
|
108
|
+
throw GradleException(
|
|
109
|
+
"[Reanimated] The feature flags `USE_ANIMATION_BACKEND` and `FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS` cannot be enabled simultaneously. If you want to use the animation backend, you need to explicitly disable `FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS` feature flag (enabled by default) in your package.json."
|
|
110
|
+
)
|
|
111
|
+
}
|
|
103
112
|
}
|
|
104
113
|
|
|
105
114
|
if (project != rootProject) {
|
|
@@ -109,6 +118,12 @@ if (project != rootProject) {
|
|
|
109
118
|
val packageDir: File = project.projectDir.parentFile
|
|
110
119
|
val reactNativeRootDir: File = resolveReactNativeDirectory()
|
|
111
120
|
val REACT_NATIVE_VERSION: String = getReactNativeVersion()
|
|
121
|
+
val IS_REACT_NATIVE_86_OR_NEWER: Boolean = run {
|
|
122
|
+
val parts = REACT_NATIVE_VERSION.split(".")
|
|
123
|
+
val major = parts.getOrNull(0)?.toIntOrNull() ?: 0
|
|
124
|
+
val minor = parts.getOrNull(1)?.toIntOrNull() ?: 0
|
|
125
|
+
major > 0 || minor >= 86
|
|
126
|
+
}
|
|
112
127
|
val REANIMATED_VERSION: String = getReanimatedVersion()
|
|
113
128
|
val IS_REANIMATED_EXAMPLE_APP: Boolean = safeAppExtGet("isReanimatedExampleApp", false)?.toString()?.toBoolean() ?: false
|
|
114
129
|
val REANIMATED_PROFILING: Boolean = safeAppExtGet("enableReanimatedProfiling", false)?.toString()?.toBoolean() ?: false
|
|
@@ -121,7 +136,11 @@ val reanimatedPrefabHeadersDir: File = project.file("${layout.buildDirectory.get
|
|
|
121
136
|
|
|
122
137
|
fun reactNativeArchitectures(): List<String> {
|
|
123
138
|
val value = project.findProperty("reactNativeArchitectures") as String?
|
|
124
|
-
return value?.split(",")
|
|
139
|
+
return value?.split(",")
|
|
140
|
+
?.map { it.trim() }
|
|
141
|
+
?.filter { it.isNotEmpty() }
|
|
142
|
+
?.ifEmpty { null }
|
|
143
|
+
?: listOf("armeabi-v7a", "x86", "x86_64", "arm64-v8a")
|
|
125
144
|
}
|
|
126
145
|
|
|
127
146
|
if (project == rootProject) {
|
|
@@ -168,6 +187,7 @@ android {
|
|
|
168
187
|
buildConfigField("String", "REANIMATED_VERSION_JAVA", "\"$REANIMATED_VERSION\"")
|
|
169
188
|
buildConfigField("boolean", "IS_INTERNAL_BUILD", "false")
|
|
170
189
|
buildConfigField("int", "EXOPACKAGE_FLAGS", "0")
|
|
190
|
+
buildConfigField("boolean", "IS_REACT_NATIVE_86_OR_NEWER", IS_REACT_NATIVE_86_OR_NEWER.toString())
|
|
171
191
|
|
|
172
192
|
@Suppress("UnstableApiUsage")
|
|
173
193
|
externalNativeBuild {
|