Fix value passed to animation's endCallback (#52038)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52038

changelog: [internal]

The changes in this diff include:
- pass endCallback with std::move to avoid copy.
- call endCallback with rawValue instead of rawValue + offset.
- remove unused method AnimationDriver::endCallback.

Reviewed By: javache

Differential Revision: D76627693

fbshipit-source-id: 8653ed3ec59b3629ad3956323b73f02a1bbd9c48
This commit is contained in:
Samuel Susla
2025-06-16 04:50:47 -07:00
committed by Facebook GitHub Bot
parent b6e1938959
commit d20b9cfdf0
6 changed files with 41 additions and 20 deletions
@@ -229,12 +229,16 @@ test('moving box by 50 points with offset 10', () => {
expect(viewElement.getBoundingClientRect().x).toBe(0);
let finishValue = null;
Fantom.runTask(() => {
Animated.timing(_translateX, {
toValue: 50,
duration: 1000, // 1 second
useNativeDriver: true,
}).start();
}).start(result => {
finishValue = result;
});
});
Fantom.runTask(() => {
@@ -260,6 +264,18 @@ test('moving box by 50 points with offset 10', () => {
.translateX,
).toBeCloseTo(60, 0.001);
expect(root.getRenderedOutput({props: ['transform']}).toJSX()).toEqual(
<rn-view transform='[{"translateX": 60.000000}]' />,
);
// TODO: this shouldn't be neccessary but C++ Animated still schedules a React state update.
Fantom.runWorkLoop();
expect(root.getRenderedOutput({props: ['transform']}).toJSX()).toEqual(
<rn-view transform='[{"translateX": 60.000000}]' />, // // must include offset.
);
expect(finishValue?.finished).toBe(true);
expect(finishValue?.value).toBe(50); // must not include offset.
expect(finishValue?.offset).toBe(10);
});
@@ -241,7 +241,7 @@ void AnimatedModule::executeOperation(const Operation& operation) {
nodesManager_->disconnectAnimatedNodes(op.parentTag, op.childTag);
} else if constexpr (std::is_same_v<T, StartAnimatingNodeOp>) {
nodesManager_->startAnimatingNode(
op.animationId, op.nodeTag, op.config, op.endCallback);
op.animationId, op.nodeTag, op.config, std::move(op.endCallback));
} else if constexpr (std::is_same_v<T, StopAnimationOp>) {
nodesManager_->stopAnimation(op.animationId, false);
} else if constexpr (std::is_same_v<T, SetAnimatedNodeValueOp>) {
@@ -274,7 +274,7 @@ void NativeAnimatedNodesManager::startAnimatingNode(
int animationId,
Tag animatedNodeTag,
const folly::dynamic& config,
const std::optional<AnimationEndCallback>& endCallback) noexcept {
std::optional<AnimationEndCallback> endCallback) noexcept {
if (auto iter = activeAnimations_.find(animationId);
iter != activeAnimations_.end()) {
// reset animation config
@@ -288,15 +288,27 @@ void NativeAnimatedNodesManager::startAnimatingNode(
switch (typeEnum.value()) {
case AnimationDriverType::Frames: {
animation = std::make_unique<FrameAnimationDriver>(
animationId, animatedNodeTag, endCallback, config, this);
animationId,
animatedNodeTag,
std::move(endCallback),
config,
this);
} break;
case AnimationDriverType::Spring: {
animation = std::make_unique<SpringAnimationDriver>(
animationId, animatedNodeTag, endCallback, config, this);
animationId,
animatedNodeTag,
std::move(endCallback),
config,
this);
} break;
case AnimationDriverType::Decay: {
animation = std::make_unique<DecayAnimationDriver>(
animationId, animatedNodeTag, endCallback, config, this);
animationId,
animatedNodeTag,
std::move(endCallback),
config,
this);
} break;
}
if (animation) {
@@ -104,7 +104,7 @@ class NativeAnimatedNodesManager {
int animationId,
Tag animatedNodeTag,
const folly::dynamic& config,
const std::optional<AnimationEndCallback>& endCallback) noexcept;
std::optional<AnimationEndCallback> endCallback) noexcept;
void stopAnimation(
int animationId,
@@ -51,16 +51,13 @@ void AnimationDriver::startAnimation() {
}
void AnimationDriver::stopAnimation(bool /*ignoreCompletedHandlers*/) {
std::optional<double> value = std::nullopt;
if (auto node =
manager_->getAnimatedNode<ValueAnimatedNode>(animatedValueTag_)) {
value = node->getValue();
} else {
LOG(ERROR)
<< "animatedValueTag should be associated with a ValueAnimatedNode";
}
if (endCallback_) {
endCallback_.value().call({.finished = true, .value = value});
manager_->getAnimatedNode<ValueAnimatedNode>(animatedValueTag_);
endCallback_) {
endCallback_.value().call(
{.finished = true,
.value = node->getRawValue(),
.offset = node->getOffset()});
}
}
@@ -42,10 +42,6 @@ class AnimationDriver {
return animatedValueTag_;
}
inline std::optional<AnimationEndCallback> endCallback() noexcept {
return endCallback_;
}
bool getIsComplete() const noexcept {
return isComplete_;
}