Skip to content

Commit 34161d8

Browse files
committed
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.
1 parent 6391443 commit 34161d8

File tree

7 files changed

+175
-7
lines changed

7 files changed

+175
-7
lines changed

vnext/Microsoft.ReactNative/Modules/Animated/AnimatedNodeType.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ enum class AnimatedNodeType {
1818
Diffclamp,
1919
Transform,
2020
Tracking,
21+
Color,
2122
};
2223

2324
static AnimatedNodeType AnimatedNodeTypeFromString(const std::string &string) {
@@ -43,7 +44,8 @@ static AnimatedNodeType AnimatedNodeTypeFromString(const std::string &string) {
4344
return AnimatedNodeType::Diffclamp;
4445
if (string == "transform")
4546
return AnimatedNodeType::Transform;
46-
47-
assert(string == "tracking");
48-
return AnimatedNodeType::Tracking;
47+
if (string == "tracking")
48+
return AnimatedNodeType::Tracking;
49+
assert(string == "color");
50+
return AnimatedNodeType::Color;
4951
};
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
#include "pch.h"
5+
6+
#include <UI.Composition.h>
7+
#include "ColorAnimatedNode.h"
8+
#include "NativeAnimatedNodeManager.h"
9+
#include <Utils/ValueUtils.h>
10+
11+
namespace Microsoft::ReactNative {
12+
ColorAnimatedNode::ColorAnimatedNode(
13+
int64_t tag,
14+
const winrt::Microsoft::ReactNative::JSValueObject &config,
15+
const std::shared_ptr<NativeAnimatedNodeManager> &manager)
16+
: AnimatedNode(tag, config, manager) {
17+
m_rNodeId = config[s_rNodeName].AsInt32();
18+
m_gNodeId = config[s_gNodeName].AsInt32();
19+
m_bNodeId = config[s_bNodeName].AsInt32();
20+
m_aNodeId = config[s_aNodeName].AsInt32();
21+
m_nativeColor = config[s_nativeColorName].Copy();
22+
23+
if (!m_useComposition) {
24+
TryApplyNativeColor();
25+
} else {
26+
assert(false && "ColorAnimatedNode not supported");
27+
}
28+
}
29+
30+
uint32_t ColorAnimatedNode::GetColor() {
31+
uint8_t r = 0;
32+
uint8_t g = 0;
33+
uint8_t b = 0;
34+
uint8_t a = 0;
35+
36+
if (const auto manager = m_manager.lock()) {
37+
if (const auto rNode = manager->GetValueAnimatedNode(m_rNodeId)) {
38+
r = std::clamp(static_cast<uint32_t>(std::round(rNode->Value())), 0u, 255u);
39+
}
40+
if (const auto gNode = manager->GetValueAnimatedNode(m_gNodeId)) {
41+
g = std::clamp(static_cast<uint32_t>(std::round(gNode->Value())), 0u, 255u);
42+
}
43+
if (const auto bNode = manager->GetValueAnimatedNode(m_bNodeId)) {
44+
b = std::clamp(static_cast<uint32_t>(std::round(bNode->Value())), 0u, 255u);
45+
}
46+
if (const auto aNode = manager->GetValueAnimatedNode(m_aNodeId)) {
47+
a = std::clamp(static_cast<uint32_t>(std::round(aNode->Value() * 255)), 0u, 255u);
48+
}
49+
}
50+
51+
const auto result = (a << 24) | (r << 16) | (g << 8) | b;
52+
return result;
53+
}
54+
55+
void ColorAnimatedNode::TryApplyNativeColor() {
56+
if (m_nativeColor.IsNull()) {
57+
return;
58+
}
59+
60+
const auto brush = BrushFromColorObject(m_nativeColor).try_as<xaml::Media::SolidColorBrush>();
61+
if (!brush) {
62+
return;
63+
}
64+
65+
if (const auto manager = m_manager.lock()) {
66+
if (const auto rNode = manager->GetValueAnimatedNode(m_rNodeId)) {
67+
rNode->RawValue(brush.Color().R);
68+
}
69+
if (const auto gNode = manager->GetValueAnimatedNode(m_gNodeId)) {
70+
gNode->RawValue(brush.Color().G);
71+
}
72+
if (const auto bNode = manager->GetValueAnimatedNode(m_bNodeId)) {
73+
bNode->RawValue(brush.Color().B);
74+
}
75+
if (const auto aNode = manager->GetValueAnimatedNode(m_aNodeId)) {
76+
aNode->RawValue(static_cast<double>(brush.Color().A) / 255);
77+
}
78+
}
79+
}
80+
81+
} // namespace Microsoft::ReactNative
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
#pragma once
5+
#include "AnimatedNode.h"
6+
7+
namespace Microsoft::ReactNative {
8+
class ColorAnimatedNode final : public AnimatedNode {
9+
public:
10+
ColorAnimatedNode(
11+
int64_t tag,
12+
const winrt::Microsoft::ReactNative::JSValueObject &config,
13+
const std::shared_ptr<NativeAnimatedNodeManager> &manager);
14+
15+
uint32_t GetColor();
16+
17+
private:
18+
void TryApplyNativeColor();
19+
20+
int32_t m_rNodeId{};
21+
int32_t m_gNodeId{};
22+
int32_t m_bNodeId{};
23+
int32_t m_aNodeId{};
24+
winrt::Microsoft::ReactNative::JSValue m_nativeColor{};
25+
26+
static constexpr std::string_view s_rNodeName{"r"};
27+
static constexpr std::string_view s_gNodeName{"g"};
28+
static constexpr std::string_view s_bNodeName{"b"};
29+
static constexpr std::string_view s_aNodeName{"a"};
30+
static constexpr std::string_view s_nativeColorName{"nativeColor"};
31+
};
32+
} // namespace Microsoft::ReactNative

vnext/Microsoft.ReactNative/Modules/Animated/NativeAnimatedNodeManager.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ void NativeAnimatedNodeManager::CreateAnimatedNode(
118118
m_trackingNodes.emplace(tag, std::make_unique<TrackingAnimatedNode>(tag, config, manager));
119119
break;
120120
}
121+
case AnimatedNodeType::Color: {
122+
m_colorNodes.emplace(tag, std::make_unique<ColorAnimatedNode>(tag, config, manager));
123+
break;
124+
}
121125
default: {
122126
assert(false);
123127
break;
@@ -483,6 +487,9 @@ AnimatedNode *NativeAnimatedNodeManager::GetAnimatedNode(int64_t tag) {
483487
if (m_trackingNodes.count(tag)) {
484488
return m_trackingNodes.at(tag).get();
485489
}
490+
if (m_colorNodes.count(tag)) {
491+
return m_colorNodes.at(tag).get();
492+
}
486493
return static_cast<AnimatedNode *>(nullptr);
487494
}
488495

@@ -521,6 +528,13 @@ TrackingAnimatedNode *NativeAnimatedNodeManager::GetTrackingAnimatedNode(int64_t
521528
return nullptr;
522529
}
523530

531+
ColorAnimatedNode *NativeAnimatedNodeManager::GetColorAnimatedNode(int64_t tag) {
532+
if (m_colorNodes.count(tag)) {
533+
return m_colorNodes.at(tag).get();
534+
}
535+
return nullptr;
536+
}
537+
524538
void NativeAnimatedNodeManager::RemoveActiveAnimation(int64_t tag) {
525539
m_activeAnimations.erase(tag);
526540
}

vnext/Microsoft.ReactNative/Modules/Animated/NativeAnimatedNodeManager.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <folly/dynamic.h>
1111
#include "AnimatedNode.h"
1212
#include "AnimationDriver.h"
13+
#include "ColorAnimatedNode.h"
1314
#include "EventAnimationDriver.h"
1415
#include "PropsAnimatedNode.h"
1516
#include "StyleAnimatedNode.h"
@@ -98,6 +99,7 @@ class NativeAnimatedNodeManager {
9899
StyleAnimatedNode *GetStyleAnimatedNode(int64_t tag);
99100
TransformAnimatedNode *GetTransformAnimatedNode(int64_t tag);
100101
TrackingAnimatedNode *GetTrackingAnimatedNode(int64_t tag);
102+
ColorAnimatedNode *GetColorAnimatedNode(int64_t tag);
101103

102104
void RemoveActiveAnimation(int64_t tag);
103105
void RemoveStoppedAnimation(int64_t tag, const std::shared_ptr<NativeAnimatedNodeManager> &manager);
@@ -122,6 +124,7 @@ class NativeAnimatedNodeManager {
122124
std::unordered_map<int64_t, std::unique_ptr<StyleAnimatedNode>> m_styleNodes{};
123125
std::unordered_map<int64_t, std::unique_ptr<TransformAnimatedNode>> m_transformNodes{};
124126
std::unordered_map<int64_t, std::unique_ptr<TrackingAnimatedNode>> m_trackingNodes{};
127+
std::unordered_map<int64_t, std::unique_ptr<ColorAnimatedNode>> m_colorNodes{};
125128
std::unordered_map<std::tuple<int64_t, std::string>, std::vector<std::unique_ptr<EventAnimationDriver>>>
126129
m_eventDrivers{};
127130
std::unordered_map<int64_t, std::shared_ptr<AnimationDriver>> m_activeAnimations{};

vnext/Microsoft.ReactNative/Modules/Animated/PropsAnimatedNode.cpp

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
#include <Fabric/Composition/CompositionContextHelper.h>
2020
#include <Fabric/Composition/CompositionUIService.h>
2121
#include <Fabric/FabricUIManagerModule.h>
22+
#elif USE_WINUI_FABRIC
23+
#include <Fabric/WinUI/Components/FrameworkElementComponentView.h>
24+
#include <Fabric/WinUI/FabricUIManagerModule.h>
2225
#endif
2326

2427
namespace Microsoft::ReactNative {
@@ -129,6 +132,15 @@ void PropsAnimatedNode::UpdateView() {
129132
} else {
130133
m_props[entry.first] = valueNode->Value();
131134
}
135+
} else if (const auto &colorNode = manager->GetColorAnimatedNode(entry.second)) {
136+
if (m_useComposition) {
137+
const auto &facade = StringToFacadeType(entry.first);
138+
if (facade != FacadeType::None) {
139+
MakeAnimation(entry.second, facade);
140+
}
141+
} else {
142+
m_props[entry.first] = colorNode->GetColor();
143+
}
132144
}
133145
}
134146
}
@@ -347,6 +359,14 @@ xaml::UIElement PropsAnimatedNode::GetUIElement() {
347359

348360
void PropsAnimatedNode::CommitProps() {
349361
#ifndef CORE_ABI
362+
#ifdef USE_WINUI_FABRIC
363+
if (auto fabricuiManager = FabricUIManager::FromProperties(m_context.Properties())) {
364+
if (fabricuiManager->synchronouslyUpdateViewOnUIThread(
365+
static_cast<facebook::react::Tag>(m_connectedViewTag), m_props)) {
366+
return;
367+
}
368+
}
369+
#endif
350370
if (const auto node = GetShadowNodeBase()) {
351371
if (!node->m_zombie) {
352372
node->updateProperties(m_props);
@@ -356,20 +376,26 @@ void PropsAnimatedNode::CommitProps() {
356376
}
357377

358378
PropsAnimatedNode::AnimationView PropsAnimatedNode::GetAnimationView() {
359-
#ifdef USE_FABRIC
379+
#ifdef USE_FABRIC_CORE
360380
if (auto fabricuiManager = FabricUIManager::FromProperties(m_context.Properties())) {
361381
auto componentView = fabricuiManager->GetViewRegistry().findComponentViewWithTag(
362382
static_cast<facebook::react::Tag>(m_connectedViewTag));
363383
if (componentView) {
384+
#ifdef USE_WINUI_FABRIC
385+
if (componentView->Element().try_as<xaml::FrameworkElement>()) {
386+
return {nullptr, std::static_pointer_cast<FrameworkElementComponentView>(componentView)};
387+
}
388+
#else
364389
return {nullptr, componentView};
390+
#endif
365391
}
366392
}
367-
#endif // USE_FABRIC
393+
#endif // USE_FABRIC_CORE
368394
#ifndef CORE_ABI
369395
if (IsRS5OrHigher()) {
370396
if (const auto shadowNodeBase = GetShadowNodeBase()) {
371397
if (const auto shadowNodeView = shadowNodeBase->GetView()) {
372-
#ifdef USE_FABRIC
398+
#ifdef USE_FABRIC_CORE
373399
return {shadowNodeView.as<xaml::UIElement>(), nullptr};
374400
#else
375401
return {shadowNodeView.as<xaml::UIElement>()};
@@ -379,7 +405,7 @@ PropsAnimatedNode::AnimationView PropsAnimatedNode::GetAnimationView() {
379405
}
380406
#endif // CORE_ABI
381407

382-
#ifdef USE_FABRIC
408+
#ifdef USE_FABRIC_CORE
383409
return {nullptr, nullptr};
384410
#else
385411
return {nullptr};
@@ -412,6 +438,9 @@ void PropsAnimatedNode::StartAnimation(
412438
}
413439
visual.StartAnimation(targetProp, animation);
414440
}
441+
#elif USE_WINUI_FABRIC
442+
} else if (view.m_componentView) {
443+
view.m_componentView->Element().as<xaml::UIElement>().StartAnimation(animation);
415444
#endif
416445
}
417446
}
@@ -427,6 +456,11 @@ comp::CompositionPropertySet PropsAnimatedNode::EnsureCenterPointPropertySet(con
427456
return view.m_componentView.as<winrt::Microsoft::ReactNative::Composition::implementation::ComponentView>()
428457
->EnsureCenterPointPropertySet();
429458
}
459+
#endif
460+
#ifdef USE_WINUI_FABRIC
461+
if (view.m_componentView) {
462+
return view.m_componentView->EnsureCenterPointPropertySet();
463+
}
430464
#endif
431465
return nullptr;
432466
}

vnext/Microsoft.ReactNative/Modules/Animated/StyleAnimatedNode.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ void StyleAnimatedNode::CollectViewUpdates(winrt::Microsoft::ReactNative::JSValu
2828
transformNode->CollectViewUpdates(propsMap);
2929
} else if (const auto node = manager->GetValueAnimatedNode(propMapping.second)) {
3030
propsMap[propMapping.first] = node->Value();
31+
} else if (const auto node = manager->GetColorAnimatedNode(propMapping.second)) {
32+
propsMap[propMapping.first] = node->GetColor();
3133
}
3234
}
3335
}

0 commit comments

Comments
 (0)