Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,23 +62,23 @@ class LayoutAnimationsProxyCommon : public facebook::react::MountingOverrideDele
const SharedComponentDescriptorRegistry &componentDescriptorRegistry,
const std::shared_ptr<const ContextContainer> &contextContainer,
jsi::Runtime &uiRuntime,
const std::shared_ptr<UIScheduler> &uiScheduler
const std::shared_ptr<UIScheduler> &uiScheduler,
const std::shared_ptr<facebook::react::UIManager> &uiManager
#ifdef ANDROID
,
const PreserveMountedTagsFunction &filterUnmountedTagsFunction,
const std::shared_ptr<facebook::react::UIManager> &uiManager,
const std::shared_ptr<facebook::react::CallInvoker> &jsInvoker
#endif
)
: layoutAnimationsManager_(layoutAnimationsManager),
contextContainer_(contextContainer),
componentDescriptorRegistry_(componentDescriptorRegistry),
uiRuntime_(uiRuntime),
uiScheduler_(uiScheduler)
uiScheduler_(uiScheduler),
uiManager_(uiManager)
#ifdef ANDROID
,
preserveMountedTags_(filterUnmountedTagsFunction),
uiManager_(uiManager),
jsInvoker_(jsInvoker)
#endif
{
Expand All @@ -98,10 +98,10 @@ class LayoutAnimationsProxyCommon : public facebook::react::MountingOverrideDele
SharedComponentDescriptorRegistry componentDescriptorRegistry_;
jsi::Runtime &uiRuntime_;
const std::shared_ptr<UIScheduler> uiScheduler_;
std::shared_ptr<facebook::react::UIManager> uiManager_;
PreserveMountedTagsFunction preserveMountedTags_;

#ifdef ANDROID
std::shared_ptr<facebook::react::UIManager> uiManager_;
std::shared_ptr<facebook::react::CallInvoker> jsInvoker_;

void restoreOpacityInCaseOfFlakyEnteringAnimation(SurfaceId surfaceId) const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ struct LayoutAnimationsProxy_Experimental : public LayoutAnimationsProxyCommon,
const SharedComponentDescriptorRegistry &componentDescriptorRegistry,
const std::shared_ptr<const ContextContainer> &contextContainer,
jsi::Runtime &uiRuntime,
const std::shared_ptr<UIScheduler> &uiScheduler
const std::shared_ptr<UIScheduler> &uiScheduler,
const std::shared_ptr<UIManager> &uiManager
#ifdef ANDROID
,
const PreserveMountedTagsFunction &filterUnmountedTagsFunction,
const std::shared_ptr<UIManager> &uiManager,
const std::shared_ptr<CallInvoker> &jsInvoker
#endif
)
Expand All @@ -80,11 +80,11 @@ struct LayoutAnimationsProxy_Experimental : public LayoutAnimationsProxyCommon,
componentDescriptorRegistry,
contextContainer,
uiRuntime,
uiScheduler
uiScheduler,
uiManager
#ifdef ANDROID
,
filterUnmountedTagsFunction,
uiManager,
jsInvoker
#endif
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <reanimated/LayoutAnimations/LayoutAnimationsProxy_Legacy.h>

#include <react/debug/react_native_assert.h>
#include <react/renderer/mounting/ShadowTree.h>
#include <react/renderer/mounting/ShadowViewMutation.h>

#include <memory>
Expand Down Expand Up @@ -58,14 +59,37 @@ std::optional<MountingTransaction> LayoutAnimationsProxy_Legacy::pullTransaction

parseRemoveMutations(movedViews, mutations, roots);

auto shouldAnimate = !surfacesToRemove_.contains(surfaceId);
surfacesToRemove_.erase(surfaceId);
// Consume the teardown mark only on the transaction that actually clears
// the root — pulls emitted for animation frames must not eat it early.
auto shouldAnimate = true;
const auto removesRootChildren = std::ranges::any_of(mutations, [surfaceId](const auto &mutation) {
return mutation.type == ShadowViewMutation::Remove && mutation.parentTag == surfaceId;
});
if (removesRootChildren) {
shouldAnimate = surfacesToRemove_.erase(surfaceId) == 0;
}
handleRemovals(filteredMutations, roots, deadNodes, shouldAnimate);

handleUpdatesAndEnterings(filteredMutations, movedViews, mutations, propsParserContext, surfaceId);

addOngoingAnimations(surfaceId, filteredMutations);

// The LayoutAnimationDriver can emit a final keyframe update in the same
// transaction as the deferred Remove/Delete it withheld for a delete
// animation. We emit removals before updates, so such an update would
// otherwise reach the mounting layer after its view was deleted.
std::unordered_set<Tag> deletedTags;
for (const auto &mutation : filteredMutations) {
if (mutation.type == ShadowViewMutation::Delete) {
deletedTags.insert(mutation.oldChildShadowView.tag);
}
}
if (!deletedTags.empty()) {
std::erase_if(filteredMutations, [&deletedTags](const auto &mutation) {
return mutation.type == ShadowViewMutation::Update && deletedTags.contains(mutation.newChildShadowView.tag);
});
}

return MountingTransaction{surfaceId, transactionNumber, std::move(filteredMutations), telemetry};
}

Expand Down Expand Up @@ -959,23 +983,22 @@ inline bool MutationNode::isMutationNode() {
return true;
}

// UIManagerAnimationDelegate

void LayoutAnimationsProxy_Legacy::uiManagerDidConfigureNextLayoutAnimation(
jsi::Runtime &runtime,
const RawValue &config,
const jsi::Value &successCallbackValue,
const jsi::Value &failureCallbackValue) const {}
// UIManagerCommitHook

void LayoutAnimationsProxy_Legacy::setComponentDescriptorRegistry(
const SharedComponentDescriptorRegistry &componentDescriptorRegistry) {}

bool LayoutAnimationsProxy_Legacy::shouldAnimateFrame() const {
return false;
}

void LayoutAnimationsProxy_Legacy::stopSurface(SurfaceId surfaceId) {
surfacesToRemove_.insert(surfaceId);
// Surface teardown commits an empty root (SurfaceHandler::stop) before the
// teardown transaction is pulled — mark it so pullTransaction skips exit
// animations. Reading the ShadowTreeRegistry here instead would deadlock (#8579).
RootShadowNode::Unshared LayoutAnimationsProxy_Legacy::shadowTreeWillCommit(
const ShadowTree &shadowTree,
const RootShadowNode::Shared & /*oldRootShadowNode*/,
const RootShadowNode::Unshared &newRootShadowNode) noexcept {
auto lock = std::unique_lock<std::recursive_mutex>(mutex);
if (newRootShadowNode->getChildren().empty()) {
surfacesToRemove_.insert(shadowTree.getSurfaceId());
} else {
surfacesToRemove_.erase(shadowTree.getSurfaceId());
}
return newRootShadowNode;
}

} // namespace reanimated
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
#include <react/renderer/componentregistry/ComponentDescriptorFactory.h>
#include <react/renderer/mounting/MountingOverrideDelegate.h>
#include <react/renderer/scheduler/Scheduler.h>
#include <react/renderer/uimanager/UIManagerAnimationDelegate.h>
#include <react/renderer/uimanager/UIManagerBinding.h>
#include <react/renderer/uimanager/UIManagerCommitHook.h>
#include <reanimated/Compat/WorkletsApi.h>
#include <reanimated/LayoutAnimations/LayoutAnimationsManager.h>
#include <reanimated/LayoutAnimations/LayoutAnimationsProxyCommon.h>
Expand Down Expand Up @@ -102,7 +102,7 @@ struct SurfaceContext {
};

struct LayoutAnimationsProxy_Legacy : public LayoutAnimationsProxyCommon,
public UIManagerAnimationDelegate,
public UIManagerCommitHook,
public std::enable_shared_from_this<LayoutAnimationsProxy_Legacy> {
mutable std::unordered_map<Tag, std::shared_ptr<Node>> nodeForTag_;
mutable std::recursive_mutex mutex;
Expand All @@ -116,11 +116,11 @@ struct LayoutAnimationsProxy_Legacy : public LayoutAnimationsProxyCommon,
const SharedComponentDescriptorRegistry &componentDescriptorRegistry,
const std::shared_ptr<const ContextContainer> &contextContainer,
jsi::Runtime &uiRuntime,
const std::shared_ptr<UIScheduler> &uiScheduler
const std::shared_ptr<UIScheduler> &uiScheduler,
const std::shared_ptr<UIManager> &uiManager
#ifdef ANDROID
,
const PreserveMountedTagsFunction &filterUnmountedTagsFunction,
const std::shared_ptr<UIManager> &uiManager,
const std::shared_ptr<CallInvoker> &jsInvoker
#endif
)
Expand All @@ -129,14 +129,19 @@ struct LayoutAnimationsProxy_Legacy : public LayoutAnimationsProxyCommon,
componentDescriptorRegistry,
contextContainer,
uiRuntime,
uiScheduler
uiScheduler,
uiManager
#ifdef ANDROID
,
filterUnmountedTagsFunction,
uiManager,
jsInvoker
#endif
) {
uiManager->registerCommitHook(*this);
}

~LayoutAnimationsProxy_Legacy() override {
uiManager_->unregisterCommitHook(*this);
}

void startEnteringAnimation(const int tag, ShadowViewMutation &mutation) const;
Expand Down Expand Up @@ -202,19 +207,15 @@ struct LayoutAnimationsProxy_Legacy : public LayoutAnimationsProxyCommon,
const TransactionTelemetry &telemetry,
ShadowViewMutationList mutations) const override;

// UIManagerAnimationDelegate

void uiManagerDidConfigureNextLayoutAnimation(
jsi::Runtime &runtime,
const RawValue &config,
const jsi::Value &successCallbackValue,
const jsi::Value &failureCallbackValue) const override;

void setComponentDescriptorRegistry(const SharedComponentDescriptorRegistry &componentDescriptorRegistry) override;
// UIManagerCommitHook

bool shouldAnimateFrame() const override;
void commitHookWasRegistered(const UIManager &uiManager) noexcept override {}
void commitHookWasUnregistered(const UIManager &uiManager) noexcept override {}

void stopSurface(SurfaceId surfaceId) override;
RootShadowNode::Unshared shadowTreeWillCommit(
const ShadowTree &shadowTree,
const RootShadowNode::Shared &oldRootShadowNode,
const RootShadowNode::Unshared &newRootShadowNode) noexcept override;
};

} // namespace reanimated
Original file line number Diff line number Diff line change
Expand Up @@ -1224,11 +1224,11 @@ void ReanimatedModuleProxy::initializeLayoutAnimationsProxy() {
componentDescriptorRegistry,
scheduler->getContextContainer(),
getJSIRuntimeFromWorkletRuntime(uiRuntime_),
uiScheduler_
uiScheduler_,
uiManager_
#ifdef ANDROID
,
filterUnmountedTagsFunction_,
uiManager_,
jsInvoker_
#endif
);
Expand All @@ -1237,22 +1237,19 @@ void ReanimatedModuleProxy::initializeLayoutAnimationsProxy() {
#endif
layoutAnimationsProxy_ = std::move(layoutAnimationsProxyExperimental);
} else {
auto layoutAnimationsProxyLegacy = std::make_shared<LayoutAnimationsProxy_Legacy>(
layoutAnimationsProxy_ = std::make_shared<LayoutAnimationsProxy_Legacy>(
layoutAnimationsManager_,
componentDescriptorRegistry,
scheduler->getContextContainer(),
getJSIRuntimeFromWorkletRuntime(uiRuntime_),
uiScheduler_
uiScheduler_,
uiManager_
#ifdef ANDROID
,
filterUnmountedTagsFunction_,
uiManager_,
jsInvoker_
#endif
);
// TODO (future): support in experimental
uiManager_->setAnimationDelegate(layoutAnimationsProxyLegacy.get());
layoutAnimationsProxy_ = std::move(layoutAnimationsProxyLegacy);
}
}
}
Expand Down
Loading