From 8d6098a645745fa964bac475ff14598d0cdfd11a Mon Sep 17 00:00:00 2001 From: Zeya Peng Date: Fri, 11 Apr 2025 10:54:07 -0700 Subject: [PATCH] create UIManagerNativeAnimatedDelegate to drive per frame NativeAnimated update Summary: ## Changelog: [Android] [Added] - create UIManagerNativeAnimatedDelegate to potentially drive per frame NativeAnimated update * I'm imitating the way LayoutAnimation kicks off (`UIManagerAnimationDelegate`); re-using `UIManager::animationTick` function to schedule per frame animation callback Reviewed By: rshest Differential Revision: D71419497 fbshipit-source-id: ba867e4c2ed2ad89a7c9229c1156e20aca45e0e9 --- .../react/fabric/FabricUIManager.java | 4 +++- .../react/renderer/uimanager/UIManager.cpp | 9 +++++++ .../react/renderer/uimanager/UIManager.h | 12 +++++++--- .../UIManagerNativeAnimatedDelegate.h | 24 +++++++++++++++++++ 4 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerNativeAnimatedDelegate.h diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index b6d031859e8..b62625bb171 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -190,6 +190,8 @@ public class FabricUIManager private boolean mDriveCxxAnimations = false; + private boolean mDriveCxxNativeAnimated = ReactNativeFeatureFlags.cxxNativeAnimatedEnabled(); + private long mDispatchViewUpdatesTime = 0l; private long mCommitStartTime = 0l; private long mLayoutTime = 0l; @@ -1373,7 +1375,7 @@ public class FabricUIManager // There is a race condition here between getting/setting // `mDriveCxxAnimations` which shouldn't matter; it's safe to call // the mBinding method, unless mBinding has gone away. - if (mDriveCxxAnimations && mBinding != null) { + if ((mDriveCxxAnimations || mDriveCxxNativeAnimated) && mBinding != null) { mBinding.driveCxxAnimations(); } diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp index 3120b863e17..d5b3c8987d5 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp @@ -664,6 +664,11 @@ void UIManager::stopSurfaceForAnimationDelegate(SurfaceId surfaceId) const { } } +void UIManager::setNativeAnimatedDelegate( + std::weak_ptr delegate) { + nativeAnimatedDelegate_ = delegate; +} + void UIManager::animationTick() const { if (animationDelegate_ != nullptr && animationDelegate_->shouldAnimateFrame()) { @@ -671,6 +676,10 @@ void UIManager::animationTick() const { shadowTree.notifyDelegatesOfUpdates(); }); } + + if (auto nativeAnimatedDelegate = nativeAnimatedDelegate_.lock()) { + nativeAnimatedDelegate->runAnimationFrame(); + } } void UIManager::synchronouslyUpdateViewOnUIThread( diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.h b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.h index 2c7e73fdd0a..1aa6df5c4f3 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.h +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,9 @@ class UIManager final : public ShadowTreeDelegate { */ void stopSurfaceForAnimationDelegate(SurfaceId surfaceId) const; + void setNativeAnimatedDelegate( + std::weak_ptr delegate); + void animationTick() const; void synchronouslyUpdateViewOnUIThread(Tag tag, const folly::dynamic& props); @@ -192,9 +196,9 @@ class UIManager final : public ShadowTreeDelegate { /* * Iterates over all shadow nodes which are parts of all registered surfaces - * and find the one that has given `tag`. Returns `nullptr` if the node wasn't - * found. This is a temporary workaround that should not be used in any core - * functionality. + * and find the one that has given `tag`. Returns `nullptr` if the node + * wasn't found. This is a temporary workaround that should not be used in + * any core functionality. */ ShadowNode::Shared findShadowNodeByTag_DEPRECATED(Tag tag) const; @@ -234,6 +238,8 @@ class UIManager final : public ShadowTreeDelegate { SharedComponentDescriptorRegistry componentDescriptorRegistry_; UIManagerDelegate* delegate_{}; UIManagerAnimationDelegate* animationDelegate_{nullptr}; + std::weak_ptr nativeAnimatedDelegate_; + const RuntimeExecutor runtimeExecutor_{}; ShadowTreeRegistry shadowTreeRegistry_{}; ContextContainer::Shared contextContainer_; diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerNativeAnimatedDelegate.h b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerNativeAnimatedDelegate.h new file mode 100644 index 00000000000..a163a3741a5 --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerNativeAnimatedDelegate.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include +#include + +namespace facebook::react { + +class UIManagerNativeAnimatedDelegate { + public: + virtual ~UIManagerNativeAnimatedDelegate() = default; + + virtual void runAnimationFrame() = 0; +}; + +} // namespace facebook::react