From a799367bafcca7bbf1cb3bea82117c470baa6f77 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Wed, 20 May 2020 14:11:18 -0700 Subject: [PATCH] LayoutAnimations: allow Paragraph props to be interpolated Summary: 1. Split out the prop interpolation function out of the View ComponentDescriptor, into an inline'd function that can be used elsewhere. 2. Call it from View and from Paragraph component descriptors. This causes animations including Text to look normal on iOS. Changelog: [Internal] Reviewed By: shergin Differential Revision: D21635473 fbshipit-source-id: 470f43fd24a6e80d8696ee2f2a09d9e693b7f280 --- .../paragraph/ParagraphComponentDescriptor.h | 13 +++++ .../components/view/ViewComponentDescriptor.h | 29 +--------- .../components/view/ViewPropsInterpolation.h | 58 +++++++++++++++++++ 3 files changed, 74 insertions(+), 26 deletions(-) create mode 100644 ReactCommon/fabric/components/view/ViewPropsInterpolation.h diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h b/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h index d360c93d33..0ec89c5683 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h @@ -9,6 +9,7 @@ #include "ParagraphShadowNode.h" +#include #include #include #include @@ -30,6 +31,18 @@ class ParagraphComponentDescriptor final textLayoutManager_ = std::make_shared(contextContainer_); } + virtual SharedProps interpolateProps( + float animationProgress, + const SharedProps &props, + const SharedProps &newProps) const override { + SharedProps interpolatedPropsShared = cloneProps(newProps, {}); + + interpolateViewProps( + animationProgress, props, newProps, interpolatedPropsShared); + + return interpolatedPropsShared; + }; + protected: void adopt(UnsharedShadowNode shadowNode) const override { ConcreteComponentDescriptor::adopt(shadowNode); diff --git a/ReactCommon/fabric/components/view/ViewComponentDescriptor.h b/ReactCommon/fabric/components/view/ViewComponentDescriptor.h index 9eaacaaa77..006081daf3 100644 --- a/ReactCommon/fabric/components/view/ViewComponentDescriptor.h +++ b/ReactCommon/fabric/components/view/ViewComponentDescriptor.h @@ -10,6 +10,7 @@ #include #include #include "ViewProps.h" +#include "ViewPropsInterpolation.h" namespace facebook { namespace react { @@ -24,34 +25,10 @@ class ViewComponentDescriptor float animationProgress, const SharedProps &props, const SharedProps &newProps) const override { - ViewProps const *oldViewProps = - dynamic_cast(props.get()); - ViewProps const *newViewProps = - dynamic_cast(newProps.get()); - SharedProps interpolatedPropsShared = cloneProps(newProps, {}); - ViewProps *interpolatedProps = const_cast( - dynamic_cast(interpolatedPropsShared.get())); - interpolatedProps->opacity = oldViewProps->opacity + - (newViewProps->opacity - oldViewProps->opacity) * animationProgress; - - interpolatedProps->transform = Transform::Interpolate( - animationProgress, oldViewProps->transform, newViewProps->transform); - - // Android uses RawProps, not props, to update props on the platform... - // Since interpolated props don't interpolate at all using RawProps, we need - // to "re-hydrate" raw props after interpolating. This is what actually gets - // sent to the mounting layer. This is a temporary hack, only for platforms - // that use RawProps/folly::dynamic instead of concrete props on the - // mounting layer. Once we can remove this, we should change `rawProps` to - // be const again. -#ifdef ANDROID - interpolatedProps->rawProps["opacity"] = interpolatedProps->opacity; - - interpolatedProps->rawProps["transform"] = - (folly::dynamic)interpolatedProps->transform; -#endif + interpolateViewProps( + animationProgress, props, newProps, interpolatedPropsShared); return interpolatedPropsShared; }; diff --git a/ReactCommon/fabric/components/view/ViewPropsInterpolation.h b/ReactCommon/fabric/components/view/ViewPropsInterpolation.h new file mode 100644 index 0000000000..0470d696d5 --- /dev/null +++ b/ReactCommon/fabric/components/view/ViewPropsInterpolation.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) Facebook, Inc. and its 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 "ViewProps.h" + +namespace facebook { +namespace react { + +/** + * Given animation progress, old props, new props, and an "interpolated" shared + * props struct, this will mutate the "interpolated" struct in-place to give it + * values interpolated between the old and new props. + */ +static inline void interpolateViewProps( + Float animationProgress, + const SharedProps &oldPropsShared, + const SharedProps &newPropsShared, + SharedProps &interpolatedPropsShared) { + ViewProps const *oldViewProps = + dynamic_cast(oldPropsShared.get()); + ViewProps const *newViewProps = + dynamic_cast(newPropsShared.get()); + ViewProps *interpolatedProps = const_cast( + dynamic_cast(interpolatedPropsShared.get())); + + assert( + oldViewProps != nullptr && newViewProps != nullptr && + interpolatedProps != nullptr); + + interpolatedProps->opacity = oldViewProps->opacity + + (newViewProps->opacity - oldViewProps->opacity) * animationProgress; + + interpolatedProps->transform = Transform::Interpolate( + animationProgress, oldViewProps->transform, newViewProps->transform); + + // Android uses RawProps, not props, to update props on the platform... + // Since interpolated props don't interpolate at all using RawProps, we need + // to "re-hydrate" raw props after interpolating. This is what actually gets + // sent to the mounting layer. This is a temporary hack, only for platforms + // that use RawProps/folly::dynamic instead of concrete props on the + // mounting layer. Once we can remove this, we should change `rawProps` to + // be const again. +#ifdef ANDROID + interpolatedProps->rawProps["opacity"] = interpolatedProps->opacity; + + interpolatedProps->rawProps["transform"] = + (folly::dynamic)interpolatedProps->transform; +#endif +} + +} // namespace react +} // namespace facebook