Skip to content

Commit 2a39a8b

Browse files
add top right support
1 parent 4f89321 commit 2a39a8b

File tree

8 files changed

+359
-37
lines changed

8 files changed

+359
-37
lines changed

packages/react-native/React/Fabric/Utils/RCTRadialGradient.mm

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,19 @@ + (CALayer *)gradientLayerWithSize:(CGSize)size gradient:(const RadialGradient &
133133
UIImage *gradientImage = [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull rendererContext) {
134134
CGContextRef context = rendererContext.CGContext;
135135

136-
CGPoint centerPoint = CGPointMake(
137-
gradient.position.x.resolve(size.width),
138-
gradient.position.y.resolve(size.height)
139-
);
136+
CGPoint centerPoint = CGPointMake(size.width / 2.0, size.height / 2.0);
137+
138+
if (gradient.position.top) {
139+
centerPoint.y = gradient.position.top->resolve(size.height);
140+
} else if (gradient.position.bottom) {
141+
centerPoint.y = size.height - gradient.position.bottom->resolve(size.height);
142+
}
143+
144+
if (gradient.position.left) {
145+
centerPoint.x = gradient.position.left->resolve(size.width);
146+
} else if (gradient.position.right) {
147+
centerPoint.x = size.width - gradient.position.right->resolve(size.width);
148+
}
140149

141150
bool isCircle = (gradient.shape == RadialGradientShape::Circle);
142151
auto [radiusX, radiusY] = GetRadialGradientRadius(

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/style/RadialGradient.kt

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -80,27 +80,52 @@ internal class RadialGradient(
8080
)
8181
}
8282

83+
private class Position(
84+
val top: LengthPercentage? = null,
85+
val left: LengthPercentage? = null,
86+
val right: LengthPercentage? = null,
87+
val bottom: LengthPercentage? = null
88+
)
89+
8390
private val shape: Shape = Shape.fromString(shapeString)
8491
private val isCircle: Boolean = shape == Shape.CIRCLE
8592

86-
private val position: Pair<LengthPercentage, LengthPercentage> = run {
87-
var x = LengthPercentage(50f, LengthPercentageType.PERCENT)
88-
var y = LengthPercentage(50f, LengthPercentageType.PERCENT)
89-
90-
if (positionMap != null) {
91-
val xIt = positionMap.getDynamic("x")
92-
val yIt = positionMap.getDynamic("y")
93-
if (xIt != null && yIt != null) {
94-
val posX = LengthPercentage.setFromDynamic(xIt)
95-
val posY = LengthPercentage.setFromDynamic(yIt)
96-
if (posX != null && posY != null) {
97-
x = posX
98-
y = posY
99-
}
100-
}
93+
private val position: Position = run {
94+
val defaultPosition = Position(
95+
top = LengthPercentage(50f, LengthPercentageType.PERCENT),
96+
left = LengthPercentage(50f, LengthPercentageType.PERCENT)
97+
)
98+
99+
if (positionMap == null) {
100+
return@run defaultPosition
101+
}
102+
103+
var top: LengthPercentage? = null
104+
var left: LengthPercentage? = null
105+
var right: LengthPercentage? = null
106+
var bottom: LengthPercentage? = null
107+
108+
if (positionMap.hasKey("top")) {
109+
val rawTop = positionMap.getDynamic("top")
110+
top = LengthPercentage.setFromDynamic(rawTop)
111+
} else if (positionMap.hasKey("bottom")) {
112+
val rawBottom = positionMap.getDynamic("bottom")
113+
bottom = LengthPercentage.setFromDynamic(rawBottom)
114+
} else {
115+
return@run defaultPosition
101116
}
102117

103-
Pair(x, y)
118+
if (positionMap.hasKey("left")) {
119+
val rawLeft = positionMap.getDynamic("left")
120+
left = LengthPercentage.setFromDynamic(rawLeft)
121+
} else if (positionMap.hasKey("right")) {
122+
val rawRight = positionMap.getDynamic("right")
123+
right = LengthPercentage.setFromDynamic(rawRight)
124+
} else {
125+
return@run defaultPosition
126+
}
127+
128+
Position(top, left, right, bottom)
104129
}
105130

106131
private val size: GradientSize = run {
@@ -164,8 +189,20 @@ internal class RadialGradient(
164189
}
165190

166191
fun getShader(width: Float, height: Float): Shader {
167-
val centerX = position.first.resolveToPixel(width)
168-
val centerY = position.second.resolveToPixel(height)
192+
var centerX: Float = width / 2f
193+
var centerY: Float = height / 2f
194+
195+
if (position.top != null) {
196+
centerY = position.top.resolveToPixel(height)
197+
} else if (position.bottom != null) {
198+
centerY = height - position.bottom.resolveToPixel(height)
199+
}
200+
201+
if (position.left != null) {
202+
centerX = position.left.resolveToPixel(width)
203+
} else if (position.right != null) {
204+
centerX = width - position.right.resolveToPixel(width)
205+
}
169206

170207
val (radiusX, radiusY) = calculateRadius(centerX, centerY, width, height)
171208

packages/react-native/ReactCommon/react/renderer/components/view/conversions.h

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,13 +1291,26 @@ inline void fromRawValue(
12911291
auto positionIt = rawBackgroundImageMap.find("position");
12921292
if (positionIt != rawBackgroundImageMap.end() && positionIt->second.hasType<std::unordered_map<std::string, RawValue>>()) {
12931293
auto positionMap = static_cast<std::unordered_map<std::string, RawValue>>(positionIt->second);
1294-
auto xIt = positionMap.find("x");
1295-
auto yIt = positionMap.find("y");
1296-
if (xIt != positionMap.end() && yIt != positionMap.end()) {
1297-
auto x = toValueUnit(xIt->second);
1298-
auto y = toValueUnit(yIt->second);
1299-
radialGradient.position.x = x;
1300-
radialGradient.position.y = y;
1294+
1295+
auto topIt = positionMap.find("top");
1296+
auto bottomIt = positionMap.find("bottom");
1297+
auto leftIt = positionMap.find("left");
1298+
auto rightIt = positionMap.find("right");
1299+
1300+
if (topIt != positionMap.end()) {
1301+
auto topValue = toValueUnit(topIt->second);
1302+
radialGradient.position.top = topValue;
1303+
} else if (bottomIt != positionMap.end()) {
1304+
auto bottomValue = toValueUnit(bottomIt->second);
1305+
radialGradient.position.bottom = bottomValue;
1306+
}
1307+
1308+
if (leftIt != positionMap.end()) {
1309+
auto leftValue = toValueUnit(leftIt->second);
1310+
radialGradient.position.left = leftValue;
1311+
} else if (rightIt != positionMap.end()) {
1312+
auto rightValue = toValueUnit(rightIt->second);
1313+
radialGradient.position.right = rightValue;
13011314
}
13021315
}
13031316
}

packages/react-native/ReactCommon/react/renderer/graphics/RadialGradient.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <string>
1414
#include <variant>
1515
#include <vector>
16+
#include <optional>
1617

1718
namespace facebook::react {
1819

@@ -58,11 +59,16 @@ struct RadialGradientSize {
5859
};
5960

6061
struct RadialGradientPosition {
61-
ValueUnit x;
62-
ValueUnit y;
62+
std::optional<ValueUnit> top;
63+
std::optional<ValueUnit> left;
64+
std::optional<ValueUnit> right;
65+
std::optional<ValueUnit> bottom;
6366

6467
bool operator==(const RadialGradientPosition& other) const {
65-
return x == other.x && y == other.y;
68+
return top == other.top &&
69+
left == other.left &&
70+
right == other.right &&
71+
bottom == other.bottom;
6672
}
6773

6874
bool operator!=(const RadialGradientPosition& other) const {

packages/rn-tester/js/examples/Playground/RNTesterPlayground.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@ import {StyleSheet, View} from 'react-native';
1818
function Playground() {
1919
return (
2020
<View style={styles.container}>
21-
<RNTesterText>
22-
Edit "RNTesterPlayground.js" to change this file
23-
</RNTesterText>
21+
<View style={styles.gradientContainer} />
2422
</View>
2523
);
2624
}
@@ -29,6 +27,12 @@ const styles = StyleSheet.create({
2927
container: {
3028
padding: 10,
3129
},
30+
gradientContainer: {
31+
width: 300,
32+
height: 200,
33+
experimental_backgroundImage: `radial-gradient(circle at top right, rgba(255, 255, 255, 0.8) 0%, transparent 50%),
34+
linear-gradient(to bottom, #43cea2, #185a9d);`,
35+
},
3236
});
3337

3438
export default ({

0 commit comments

Comments
 (0)