mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-06 07:06:11 +00:00
feat: improve animating colors (#2471)
# Summary
Currently on Fabric, you cannot animate color properties like `fill` or
`stroke` using Animated with `useNativeDriver: true` or Reanimated.
That's because we have custom structure that needs to be parsed on `JS`
and looks like:
```ts
type ColorStruct = Readonly<{
type?: WithDefault<Int32, -1>;
payload?: ColorValue;
brushRef?: string;
}>;
```
However, special values like `currentColor` / `context-fill` /
`context-stroke` / `/^url\(#(.+)\)$/` can not be animated anyway.
Instead, we should allow passing `ColorValue` directly and detect on the
native side if its ColorValue or ColorStruct.
## Test Plan
Example app -> TestX
## Compatibility
| OS | Implemented |
| ------- | :---------: |
| iOS | ✅ |
| MacOS | ✅ |
| Android | ✅ |
## Checklist
- [x] I have tested this on a device and a simulator
- [ ] I added documentation in `README.md`
This commit is contained in:
@@ -55,38 +55,6 @@ static id RNSVGConvertFollyDynamicToId(const folly::dynamic &dyn)
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
RNSVGBrush *brushFromColorStruct(const T &fillObject)
|
||||
{
|
||||
int type = fillObject.type;
|
||||
|
||||
switch (type) {
|
||||
case -1: // empty struct
|
||||
return nil;
|
||||
case 0: // solid color
|
||||
{
|
||||
// These are probably expensive allocations since it's often the same value.
|
||||
// We should memoize colors but look ups may be just as expensive.
|
||||
RNSVGColor *color = RCTUIColorFromSharedColor(fillObject.payload) ?: [RNSVGColor clearColor];
|
||||
return [[RNSVGSolidColorBrush alloc] initWithColor:color];
|
||||
}
|
||||
case 1: // brush
|
||||
{
|
||||
NSArray *arr = @[ @(type), RCTNSStringFromString(fillObject.brushRef) ];
|
||||
return [[RNSVGPainterBrush alloc] initWithArray:arr];
|
||||
}
|
||||
case 2: // currentColor
|
||||
return [[RNSVGBrush alloc] initWithArray:nil];
|
||||
case 3: // context-fill
|
||||
return [[RNSVGContextBrush alloc] initFill];
|
||||
case 4: // context-stroke
|
||||
return [[RNSVGContextBrush alloc] initStroke];
|
||||
default:
|
||||
RCTLogError(@"Unknown brush type: %d", type);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void setCommonNodeProps(const T &nodeProps, RNSVGNode *node)
|
||||
{
|
||||
@@ -143,10 +111,16 @@ void setCommonRenderableProps(const T &renderableProps, RNSVGRenderable *rendera
|
||||
if (RCTUIColorFromSharedColor(renderableProps.color)) {
|
||||
[renderableNode setColor:RCTUIColorFromSharedColor(renderableProps.color)];
|
||||
}
|
||||
renderableNode.fill = brushFromColorStruct(renderableProps.fill);
|
||||
id fill = RNSVGConvertFollyDynamicToId(renderableProps.fill);
|
||||
if (fill != nil) {
|
||||
renderableNode.fill = [RCTConvert RNSVGBrush:fill];
|
||||
}
|
||||
renderableNode.fillOpacity = renderableProps.fillOpacity;
|
||||
renderableNode.fillRule = renderableProps.fillRule == 0 ? kRNSVGCGFCRuleEvenodd : kRNSVGCGFCRuleNonzero;
|
||||
renderableNode.stroke = brushFromColorStruct(renderableProps.stroke);
|
||||
id stroke = RNSVGConvertFollyDynamicToId(renderableProps.stroke);
|
||||
if (stroke != nil) {
|
||||
renderableNode.stroke = [RCTConvert RNSVGBrush:stroke];
|
||||
}
|
||||
renderableNode.strokeOpacity = renderableProps.strokeOpacity;
|
||||
id strokeWidth = RNSVGConvertFollyDynamicToId(renderableProps.strokeWidth);
|
||||
if (strokeWidth != nil) {
|
||||
|
||||
Reference in New Issue
Block a user