From 467b4f4a1bef0fea47c361cf2babe8d19c8dc767 Mon Sep 17 00:00:00 2001 From: Eric Rozell Date: Thu, 28 Mar 2024 09:39:45 -0400 Subject: [PATCH 1/5] Adds color animated nodes to tick-driven animations This change adds color animation support when `platformConfig: { useComposition: false }` is set. It unblocks usage of Animated.Color nodes with the NativeAnimated module. --- .../Modules/Animated/AnimatedNodeType.h | 8 +- .../Modules/Animated/ColorAnimatedNode.cpp | 81 +++++++++++++++++++ .../Modules/Animated/ColorAnimatedNode.h | 32 ++++++++ .../Animated/NativeAnimatedNodeManager.cpp | 14 ++++ .../Animated/NativeAnimatedNodeManager.h | 3 + .../Modules/Animated/PropsAnimatedNode.cpp | 9 +++ .../Modules/Animated/StyleAnimatedNode.cpp | 2 + 7 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 vnext/Microsoft.ReactNative/Modules/Animated/ColorAnimatedNode.cpp create mode 100644 vnext/Microsoft.ReactNative/Modules/Animated/ColorAnimatedNode.h diff --git a/vnext/Microsoft.ReactNative/Modules/Animated/AnimatedNodeType.h b/vnext/Microsoft.ReactNative/Modules/Animated/AnimatedNodeType.h index c33141874b1..c594aeebcc8 100644 --- a/vnext/Microsoft.ReactNative/Modules/Animated/AnimatedNodeType.h +++ b/vnext/Microsoft.ReactNative/Modules/Animated/AnimatedNodeType.h @@ -18,6 +18,7 @@ enum class AnimatedNodeType { Diffclamp, Transform, Tracking, + Color, }; static AnimatedNodeType AnimatedNodeTypeFromString(const std::string &string) { @@ -43,7 +44,8 @@ static AnimatedNodeType AnimatedNodeTypeFromString(const std::string &string) { return AnimatedNodeType::Diffclamp; if (string == "transform") return AnimatedNodeType::Transform; - - assert(string == "tracking"); - return AnimatedNodeType::Tracking; + if (string == "tracking") + return AnimatedNodeType::Tracking; + assert(string == "color"); + return AnimatedNodeType::Color; }; diff --git a/vnext/Microsoft.ReactNative/Modules/Animated/ColorAnimatedNode.cpp b/vnext/Microsoft.ReactNative/Modules/Animated/ColorAnimatedNode.cpp new file mode 100644 index 00000000000..e950ff35757 --- /dev/null +++ b/vnext/Microsoft.ReactNative/Modules/Animated/ColorAnimatedNode.cpp @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "pch.h" + +#include +#include "ColorAnimatedNode.h" +#include "NativeAnimatedNodeManager.h" +#include + +namespace Microsoft::ReactNative { +ColorAnimatedNode::ColorAnimatedNode( + int64_t tag, + const winrt::Microsoft::ReactNative::JSValueObject &config, + const std::shared_ptr &manager) + : AnimatedNode(tag, config, manager) { + m_rNodeId = config[s_rNodeName].AsInt32(); + m_gNodeId = config[s_gNodeName].AsInt32(); + m_bNodeId = config[s_bNodeName].AsInt32(); + m_aNodeId = config[s_aNodeName].AsInt32(); + m_nativeColor = config[s_nativeColorName].Copy(); + + if (!m_useComposition) { + TryApplyNativeColor(); + } else { + assert(false && "ColorAnimatedNode not supported"); + } +} + +uint32_t ColorAnimatedNode::GetColor() { + uint8_t r = 0; + uint8_t g = 0; + uint8_t b = 0; + uint8_t a = 0; + + if (const auto manager = m_manager.lock()) { + if (const auto rNode = manager->GetValueAnimatedNode(m_rNodeId)) { + r = std::clamp(static_cast(std::round(rNode->Value())), 0u, 255u); + } + if (const auto gNode = manager->GetValueAnimatedNode(m_gNodeId)) { + g = std::clamp(static_cast(std::round(gNode->Value())), 0u, 255u); + } + if (const auto bNode = manager->GetValueAnimatedNode(m_bNodeId)) { + b = std::clamp(static_cast(std::round(bNode->Value())), 0u, 255u); + } + if (const auto aNode = manager->GetValueAnimatedNode(m_aNodeId)) { + a = std::clamp(static_cast(std::round(aNode->Value() * 255)), 0u, 255u); + } + } + + const auto result = (a << 24) | (r << 16) | (g << 8) | b; + return result; +} + +void ColorAnimatedNode::TryApplyNativeColor() { + if (m_nativeColor.IsNull()) { + return; + } + + const auto brush = BrushFromColorObject(m_nativeColor).try_as(); + if (!brush) { + return; + } + + if (const auto manager = m_manager.lock()) { + if (const auto rNode = manager->GetValueAnimatedNode(m_rNodeId)) { + rNode->RawValue(brush.Color().R); + } + if (const auto gNode = manager->GetValueAnimatedNode(m_gNodeId)) { + gNode->RawValue(brush.Color().G); + } + if (const auto bNode = manager->GetValueAnimatedNode(m_bNodeId)) { + bNode->RawValue(brush.Color().B); + } + if (const auto aNode = manager->GetValueAnimatedNode(m_aNodeId)) { + aNode->RawValue(static_cast(brush.Color().A) / 255); + } + } +} + +} // namespace Microsoft::ReactNative diff --git a/vnext/Microsoft.ReactNative/Modules/Animated/ColorAnimatedNode.h b/vnext/Microsoft.ReactNative/Modules/Animated/ColorAnimatedNode.h new file mode 100644 index 00000000000..917463f7872 --- /dev/null +++ b/vnext/Microsoft.ReactNative/Modules/Animated/ColorAnimatedNode.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once +#include "AnimatedNode.h" + +namespace Microsoft::ReactNative { +class ColorAnimatedNode final : public AnimatedNode { + public: + ColorAnimatedNode( + int64_t tag, + const winrt::Microsoft::ReactNative::JSValueObject &config, + const std::shared_ptr &manager); + + uint32_t GetColor(); + + private: + void TryApplyNativeColor(); + + int32_t m_rNodeId{}; + int32_t m_gNodeId{}; + int32_t m_bNodeId{}; + int32_t m_aNodeId{}; + winrt::Microsoft::ReactNative::JSValue m_nativeColor{}; + + static constexpr std::string_view s_rNodeName{"r"}; + static constexpr std::string_view s_gNodeName{"g"}; + static constexpr std::string_view s_bNodeName{"b"}; + static constexpr std::string_view s_aNodeName{"a"}; + static constexpr std::string_view s_nativeColorName{"nativeColor"}; +}; +} // namespace Microsoft::ReactNative diff --git a/vnext/Microsoft.ReactNative/Modules/Animated/NativeAnimatedNodeManager.cpp b/vnext/Microsoft.ReactNative/Modules/Animated/NativeAnimatedNodeManager.cpp index 2076e8672b6..fe0bc6fa44b 100644 --- a/vnext/Microsoft.ReactNative/Modules/Animated/NativeAnimatedNodeManager.cpp +++ b/vnext/Microsoft.ReactNative/Modules/Animated/NativeAnimatedNodeManager.cpp @@ -118,6 +118,10 @@ void NativeAnimatedNodeManager::CreateAnimatedNode( m_trackingNodes.emplace(tag, std::make_unique(tag, config, manager)); break; } + case AnimatedNodeType::Color: { + m_colorNodes.emplace(tag, std::make_unique(tag, config, manager)); + break; + } default: { assert(false); break; @@ -483,6 +487,9 @@ AnimatedNode *NativeAnimatedNodeManager::GetAnimatedNode(int64_t tag) { if (m_trackingNodes.count(tag)) { return m_trackingNodes.at(tag).get(); } + if (m_colorNodes.count(tag)) { + return m_colorNodes.at(tag).get(); + } return static_cast(nullptr); } @@ -521,6 +528,13 @@ TrackingAnimatedNode *NativeAnimatedNodeManager::GetTrackingAnimatedNode(int64_t return nullptr; } +ColorAnimatedNode *NativeAnimatedNodeManager::GetColorAnimatedNode(int64_t tag) { + if (m_colorNodes.count(tag)) { + return m_colorNodes.at(tag).get(); + } + return nullptr; +} + void NativeAnimatedNodeManager::RemoveActiveAnimation(int64_t tag) { m_activeAnimations.erase(tag); } diff --git a/vnext/Microsoft.ReactNative/Modules/Animated/NativeAnimatedNodeManager.h b/vnext/Microsoft.ReactNative/Modules/Animated/NativeAnimatedNodeManager.h index 312ddb0bcd4..db21f7344c8 100644 --- a/vnext/Microsoft.ReactNative/Modules/Animated/NativeAnimatedNodeManager.h +++ b/vnext/Microsoft.ReactNative/Modules/Animated/NativeAnimatedNodeManager.h @@ -10,6 +10,7 @@ #include #include "AnimatedNode.h" #include "AnimationDriver.h" +#include "ColorAnimatedNode.h" #include "EventAnimationDriver.h" #include "PropsAnimatedNode.h" #include "StyleAnimatedNode.h" @@ -98,6 +99,7 @@ class NativeAnimatedNodeManager { StyleAnimatedNode *GetStyleAnimatedNode(int64_t tag); TransformAnimatedNode *GetTransformAnimatedNode(int64_t tag); TrackingAnimatedNode *GetTrackingAnimatedNode(int64_t tag); + ColorAnimatedNode *GetColorAnimatedNode(int64_t tag); void RemoveActiveAnimation(int64_t tag); void RemoveStoppedAnimation(int64_t tag, const std::shared_ptr &manager); @@ -122,6 +124,7 @@ class NativeAnimatedNodeManager { std::unordered_map> m_styleNodes{}; std::unordered_map> m_transformNodes{}; std::unordered_map> m_trackingNodes{}; + std::unordered_map> m_colorNodes{}; std::unordered_map, std::vector>> m_eventDrivers{}; std::unordered_map> m_activeAnimations{}; diff --git a/vnext/Microsoft.ReactNative/Modules/Animated/PropsAnimatedNode.cpp b/vnext/Microsoft.ReactNative/Modules/Animated/PropsAnimatedNode.cpp index 2511043c178..931184195b2 100644 --- a/vnext/Microsoft.ReactNative/Modules/Animated/PropsAnimatedNode.cpp +++ b/vnext/Microsoft.ReactNative/Modules/Animated/PropsAnimatedNode.cpp @@ -129,6 +129,15 @@ void PropsAnimatedNode::UpdateView() { } else { m_props[entry.first] = valueNode->Value(); } + } else if (const auto &colorNode = manager->GetColorAnimatedNode(entry.second)) { + if (m_useComposition) { + const auto &facade = StringToFacadeType(entry.first); + if (facade != FacadeType::None) { + MakeAnimation(entry.second, facade); + } + } else { + m_props[entry.first] = colorNode->GetColor(); + } } } } diff --git a/vnext/Microsoft.ReactNative/Modules/Animated/StyleAnimatedNode.cpp b/vnext/Microsoft.ReactNative/Modules/Animated/StyleAnimatedNode.cpp index ef5499166d6..d3c195c9d7c 100644 --- a/vnext/Microsoft.ReactNative/Modules/Animated/StyleAnimatedNode.cpp +++ b/vnext/Microsoft.ReactNative/Modules/Animated/StyleAnimatedNode.cpp @@ -28,6 +28,8 @@ void StyleAnimatedNode::CollectViewUpdates(winrt::Microsoft::ReactNative::JSValu transformNode->CollectViewUpdates(propsMap); } else if (const auto node = manager->GetValueAnimatedNode(propMapping.second)) { propsMap[propMapping.first] = node->Value(); + } else if (const auto node = manager->GetColorAnimatedNode(propMapping.second)) { + propsMap[propMapping.first] = node->GetColor(); } } } From 9f469e8dce831777e5be4c3ad47623864e5f6d43 Mon Sep 17 00:00:00 2001 From: Eric Rozell Date: Thu, 28 Mar 2024 09:44:09 -0400 Subject: [PATCH 2/5] Change files --- ...ative-windows-c6908db9-21b8-4875-8d44-30c63ff13f74.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/react-native-windows-c6908db9-21b8-4875-8d44-30c63ff13f74.json diff --git a/change/react-native-windows-c6908db9-21b8-4875-8d44-30c63ff13f74.json b/change/react-native-windows-c6908db9-21b8-4875-8d44-30c63ff13f74.json new file mode 100644 index 00000000000..d5fc0970c8e --- /dev/null +++ b/change/react-native-windows-c6908db9-21b8-4875-8d44-30c63ff13f74.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "Adds color animated nodes to tick-driven animations", + "packageName": "react-native-windows", + "email": "ericroz@meta.com", + "dependentChangeType": "patch" +} From 2c729532c8c8a597eb5edf9aa4010bccda038825 Mon Sep 17 00:00:00 2001 From: Eric Rozell Date: Thu, 28 Mar 2024 09:51:09 -0400 Subject: [PATCH 3/5] Adds color value interpolation handling to tick-driven NativeAnimated driver To avoid overcomplicating the base ValueAnimatedNode, this change uses memcpy to stuff the interpolated color value into the double `value` field in the ValueAnimatedNode, and reads it out as a color type if the output type is set. --- .../Modules/Animated/ColorAnimatedNode.cpp | 2 +- .../Animated/InterpolationAnimatedNode.cpp | 83 +++++++++++++++++-- .../Animated/InterpolationAnimatedNode.h | 12 ++- .../Modules/Animated/PropsAnimatedNode.cpp | 10 +++ .../Modules/Animated/StyleAnimatedNode.cpp | 9 +- .../Modules/Animated/ValueAnimatedNode.h | 4 + 6 files changed, 109 insertions(+), 11 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Modules/Animated/ColorAnimatedNode.cpp b/vnext/Microsoft.ReactNative/Modules/Animated/ColorAnimatedNode.cpp index e950ff35757..0272b2498e0 100644 --- a/vnext/Microsoft.ReactNative/Modules/Animated/ColorAnimatedNode.cpp +++ b/vnext/Microsoft.ReactNative/Modules/Animated/ColorAnimatedNode.cpp @@ -4,9 +4,9 @@ #include "pch.h" #include +#include #include "ColorAnimatedNode.h" #include "NativeAnimatedNodeManager.h" -#include namespace Microsoft::ReactNative { ColorAnimatedNode::ColorAnimatedNode( diff --git a/vnext/Microsoft.ReactNative/Modules/Animated/InterpolationAnimatedNode.cpp b/vnext/Microsoft.ReactNative/Modules/Animated/InterpolationAnimatedNode.cpp index 96beefa0137..f086f0aa1e3 100644 --- a/vnext/Microsoft.ReactNative/Modules/Animated/InterpolationAnimatedNode.cpp +++ b/vnext/Microsoft.ReactNative/Modules/Animated/InterpolationAnimatedNode.cpp @@ -7,8 +7,21 @@ #include "ExtrapolationType.h" #include "InterpolationAnimatedNode.h" #include "NativeAnimatedNodeManager.h" +#include "Utils/ValueUtils.h" namespace Microsoft::ReactNative { + +inline int32_t ColorToInt(winrt::Windows::UI::Color color) { + return static_cast(color.A) << 24 | static_cast(color.R) << 16 | + static_cast(color.G) << 8 | static_cast(color.B); +} + +inline uint8_t ScaleByte(uint8_t min, uint8_t max, double ratio) { + const auto scaledValue = min + (max - min) * ratio; + const auto clampedValue = std::clamp(static_cast(std::round(scaledValue)), 0u, 255u); + return static_cast(clampedValue); +} + InterpolationAnimatedNode::InterpolationAnimatedNode( int64_t tag, const winrt::Microsoft::ReactNative::JSValueObject &config, @@ -17,8 +30,18 @@ InterpolationAnimatedNode::InterpolationAnimatedNode( for (const auto &rangeValue : config[s_inputRangeName].AsArray()) { m_inputRanges.push_back(rangeValue.AsDouble()); } - for (const auto &rangeValue : config[s_outputRangeName].AsArray()) { - m_outputRanges.push_back(rangeValue.AsDouble()); + + const auto isColorOutput = config[s_outputTypeName].AsString() == s_colorOutputType; + if (!m_useComposition && isColorOutput) { + m_isColorOutput = true; + for (const auto &rangeValue : config[s_outputRangeName].AsArray()) { + m_colorOutputRanges.push_back(ColorFrom(rangeValue)); + } + } else { + assert(!isColorOutput && "Color interpolation not supported"); + for (const auto &rangeValue : config[s_outputRangeName].AsArray()) { + m_defaultOutputRanges.push_back(rangeValue.AsDouble()); + } } m_extrapolateLeft = config[s_extrapolateLeftName].AsString(); @@ -33,7 +56,11 @@ void InterpolationAnimatedNode::Update() { if (const auto manager = m_manager.lock()) { if (const auto node = manager->GetValueAnimatedNode(m_parentTag)) { - RawValue(InterpolateValue(node->Value())); + if (m_isColorOutput) { + RawValue(InterpolateColor(node->Value())); + } else { + RawValue(InterpolateValue(node->Value())); + } } } } @@ -95,8 +122,9 @@ comp::ExpressionAnimation InterpolationAnimatedNode::CreateExpressionAnimation( for (size_t i = 0; i < m_inputRanges.size(); i++) { animation.SetScalarParameter(s_inputName.data() + std::to_wstring(i), static_cast(m_inputRanges[i])); } - for (size_t i = 0; i < m_outputRanges.size(); i++) { - animation.SetScalarParameter(s_outputName.data() + std::to_wstring(i), static_cast(m_outputRanges[i])); + for (size_t i = 0; i < m_defaultOutputRanges.size(); i++) { + animation.SetScalarParameter( + s_outputName.data() + std::to_wstring(i), static_cast(m_defaultOutputRanges[i])); } return animation; } @@ -173,7 +201,7 @@ winrt::hstring InterpolationAnimatedNode::GetRightExpression( const winrt::hstring &value, const winrt::hstring &rightInterpolateExpression) { const auto lastInput = s_inputName.data() + std::to_wstring(m_inputRanges.size() - 1); - const auto lastOutput = s_outputName.data() + std::to_wstring(m_outputRanges.size() - 1); + const auto lastOutput = s_outputName.data() + std::to_wstring(m_defaultOutputRanges.size() - 1); switch (ExtrapolationTypeFromString(m_extrapolateRight)) { case ExtrapolationType::Clamp: return value + L" > " + lastInput + L" ? " + lastOutput + L" : "; @@ -200,10 +228,49 @@ double InterpolationAnimatedNode::InterpolateValue(double value) { value, m_inputRanges[index], m_inputRanges[index + 1], - m_outputRanges[index], - m_outputRanges[index + 1], + m_defaultOutputRanges[index], + m_defaultOutputRanges[index + 1], m_extrapolateLeft, m_extrapolateRight); } +double InterpolationAnimatedNode::InterpolateColor(double value) { + // Compute range index + size_t index = 1; + for (; index < m_inputRanges.size() - 1; ++index) { + if (m_inputRanges[index] >= value) { + break; + } + } + index--; + + double result; + const auto outputMin = m_colorOutputRanges[index]; + const auto outputMax = m_colorOutputRanges[index + 1]; + const auto outputMinInt = ColorToInt(outputMin); + const auto outputMaxInt = ColorToInt(outputMax); + if (outputMin == outputMax) { + memcpy(&result, &outputMinInt, sizeof(int32_t)); + return result; + } + + const auto inputMin = m_inputRanges[index]; + const auto inputMax = m_inputRanges[index + 1]; + if (inputMin == inputMax) { + if (value <= inputMin) { + memcpy(&result, &outputMinInt, sizeof(int32_t)); + } else { + memcpy(&result, &outputMaxInt, sizeof(int32_t)); + } + return result; + } + + const auto ratio = (value - inputMin) / (inputMax - inputMin); + const auto interpolatedColor = ScaleByte(outputMin.A, outputMax.A, ratio) << 24 | + ScaleByte(outputMin.R, outputMax.R, ratio) << 16 | ScaleByte(outputMin.G, outputMax.G, ratio) << 8 | + ScaleByte(outputMin.B, outputMax.B, ratio); + memcpy(&result, &interpolatedColor, sizeof(int32_t)); + return result; +} + } // namespace Microsoft::ReactNative diff --git a/vnext/Microsoft.ReactNative/Modules/Animated/InterpolationAnimatedNode.h b/vnext/Microsoft.ReactNative/Modules/Animated/InterpolationAnimatedNode.h index 84321c4ee91..6d738584dd8 100644 --- a/vnext/Microsoft.ReactNative/Modules/Animated/InterpolationAnimatedNode.h +++ b/vnext/Microsoft.ReactNative/Modules/Animated/InterpolationAnimatedNode.h @@ -17,6 +17,10 @@ class InterpolationAnimatedNode final : public ValueAnimatedNode { virtual void OnDetachedFromNode(int64_t animatedNodeTag) override; virtual void OnAttachToNode(int64_t animatedNodeTag) override; + bool IsColorValue() override { + return m_isColorOutput; + } + static constexpr std::string_view ExtrapolateTypeIdentity = "identity"; static constexpr std::string_view ExtrapolateTypeClamp = "clamp"; static constexpr std::string_view ExtrapolateTypeExtend = "extend"; @@ -35,11 +39,14 @@ class InterpolationAnimatedNode final : public ValueAnimatedNode { winrt::hstring GetRightExpression(const winrt::hstring &, const winrt::hstring &rightInterpolateExpression); double InterpolateValue(double value); + double InterpolateColor(double value); comp::ExpressionAnimation m_rawValueAnimation{nullptr}; comp::ExpressionAnimation m_offsetAnimation{nullptr}; + bool m_isColorOutput{false}; std::vector m_inputRanges; - std::vector m_outputRanges; + std::vector m_defaultOutputRanges; + std::vector m_colorOutputRanges; std::string m_extrapolateLeft; std::string m_extrapolateRight; @@ -49,9 +56,12 @@ class InterpolationAnimatedNode final : public ValueAnimatedNode { static constexpr std::string_view s_inputRangeName{"inputRange"}; static constexpr std::string_view s_outputRangeName{"outputRange"}; + static constexpr std::string_view s_outputTypeName{"outputType"}; static constexpr std::string_view s_extrapolateLeftName{"extrapolateLeft"}; static constexpr std::string_view s_extrapolateRightName{"extrapolateRight"}; + static constexpr std::string_view s_colorOutputType{"color"}; + static constexpr std::wstring_view s_parentPropsName{L"p"}; static constexpr std::wstring_view s_inputName{L"i"}; static constexpr std::wstring_view s_outputName{L"o"}; diff --git a/vnext/Microsoft.ReactNative/Modules/Animated/PropsAnimatedNode.cpp b/vnext/Microsoft.ReactNative/Modules/Animated/PropsAnimatedNode.cpp index 931184195b2..edcf9001169 100644 --- a/vnext/Microsoft.ReactNative/Modules/Animated/PropsAnimatedNode.cpp +++ b/vnext/Microsoft.ReactNative/Modules/Animated/PropsAnimatedNode.cpp @@ -126,6 +126,11 @@ void PropsAnimatedNode::UpdateView() { if (facade != FacadeType::None) { MakeAnimation(entry.second, facade); } + } else if (valueNode->IsColorValue()) { + const auto value = valueNode->Value(); + int32_t color; + memcpy(&color, &value, sizeof(int32_t)); + m_props[entry.first] = color; } else { m_props[entry.first] = valueNode->Value(); } @@ -135,6 +140,11 @@ void PropsAnimatedNode::UpdateView() { if (facade != FacadeType::None) { MakeAnimation(entry.second, facade); } + } else if (valueNode->IsColorValue()) { + const auto value = valueNode->Value(); + int32_t color; + memcpy(&color, &value, sizeof(int32_t)); + m_props[entry.first] = color; } else { m_props[entry.first] = colorNode->GetColor(); } diff --git a/vnext/Microsoft.ReactNative/Modules/Animated/StyleAnimatedNode.cpp b/vnext/Microsoft.ReactNative/Modules/Animated/StyleAnimatedNode.cpp index d3c195c9d7c..a2fcd02e818 100644 --- a/vnext/Microsoft.ReactNative/Modules/Animated/StyleAnimatedNode.cpp +++ b/vnext/Microsoft.ReactNative/Modules/Animated/StyleAnimatedNode.cpp @@ -27,7 +27,14 @@ void StyleAnimatedNode::CollectViewUpdates(winrt::Microsoft::ReactNative::JSValu if (const auto transformNode = manager->GetTransformAnimatedNode(propMapping.second)) { transformNode->CollectViewUpdates(propsMap); } else if (const auto node = manager->GetValueAnimatedNode(propMapping.second)) { - propsMap[propMapping.first] = node->Value(); + if (node->IsColorValue()) { + const auto value = node->Value(); + int32_t color; + memcpy(&color, &value, sizeof(int32_t)); + propsMap[propMapping.first] = color; + } else { + propsMap[propMapping.first] = node->Value(); + } } else if (const auto node = manager->GetColorAnimatedNode(propMapping.second)) { propsMap[propMapping.first] = node->GetColor(); } diff --git a/vnext/Microsoft.ReactNative/Modules/Animated/ValueAnimatedNode.h b/vnext/Microsoft.ReactNative/Modules/Animated/ValueAnimatedNode.h index 96281f8edfe..ac0f38680dc 100644 --- a/vnext/Microsoft.ReactNative/Modules/Animated/ValueAnimatedNode.h +++ b/vnext/Microsoft.ReactNative/Modules/Animated/ValueAnimatedNode.h @@ -31,6 +31,10 @@ class ValueAnimatedNode : public AnimatedNode { void OnValueUpdate(); void ValueListener(const ValueListenerCallback &callback); + virtual bool IsColorValue() { + return false; + } + comp::CompositionPropertySet PropertySet() { return m_propertySet; }; From d81d3f17b561a41fb161859b955002ff92eca3ef Mon Sep 17 00:00:00 2001 From: Eric Rozell Date: Fri, 29 Mar 2024 10:44:09 -0400 Subject: [PATCH 4/5] Adds missing entries in msbuild files --- vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj | 2 ++ .../Microsoft.ReactNative.vcxproj.filters | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj index 932722fbf5f..f07b7927dbd 100644 --- a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +++ b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj @@ -233,6 +233,7 @@ + @@ -437,6 +438,7 @@ + diff --git a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters index ad0c2b22282..831b3467a4c 100644 --- a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters +++ b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters @@ -39,6 +39,9 @@ Modules\Animated + + Modules\Animated + Modules\Animated @@ -383,6 +386,9 @@ Modules\Animated + + Modules\Animated + Modules\Animated From 22dfa338e667bd4ecd8cb2b18dbe45ef47212194 Mon Sep 17 00:00:00 2001 From: Eric Rozell Date: Fri, 29 Mar 2024 11:53:24 -0400 Subject: [PATCH 5/5] Fix oversight in static cast --- .../Modules/Animated/ColorAnimatedNode.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Modules/Animated/ColorAnimatedNode.cpp b/vnext/Microsoft.ReactNative/Modules/Animated/ColorAnimatedNode.cpp index 0272b2498e0..ec5f080ecc6 100644 --- a/vnext/Microsoft.ReactNative/Modules/Animated/ColorAnimatedNode.cpp +++ b/vnext/Microsoft.ReactNative/Modules/Animated/ColorAnimatedNode.cpp @@ -28,10 +28,10 @@ ColorAnimatedNode::ColorAnimatedNode( } uint32_t ColorAnimatedNode::GetColor() { - uint8_t r = 0; - uint8_t g = 0; - uint8_t b = 0; - uint8_t a = 0; + uint32_t r = 0; + uint32_t g = 0; + uint32_t b = 0; + uint32_t a = 0; if (const auto manager = m_manager.lock()) { if (const auto rNode = manager->GetValueAnimatedNode(m_rNodeId)) {