Skip to content

Commit 467b4f4

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 467b4f4

File tree

7 files changed

+146
-3
lines changed

7 files changed

+146
-3
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: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,15 @@ void PropsAnimatedNode::UpdateView() {
129129
} else {
130130
m_props[entry.first] = valueNode->Value();
131131
}
132+
} else if (const auto &colorNode = manager->GetColorAnimatedNode(entry.second)) {
133+
if (m_useComposition) {
134+
const auto &facade = StringToFacadeType(entry.first);
135+
if (facade != FacadeType::None) {
136+
MakeAnimation(entry.second, facade);
137+
}
138+
} else {
139+
m_props[entry.first] = colorNode->GetColor();
140+
}
132141
}
133142
}
134143
}

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)