From 78aaffad104f26870bf160e8d37bcb7f6918fa74 Mon Sep 17 00:00:00 2001 From: Wojciech Lewicki Date: Fri, 7 Jul 2023 11:21:04 +0200 Subject: [PATCH] feat: strokeDasharray with Animated (#2089) PR adding the proper handling of strokeDasharray prop for when used with Animated and Reanimated. Code based on #1464 by @bardliu, but with the newest state of the repository. --- TestsExample/App.js | 3 +- TestsExample/src/Test2089.tsx | 66 +++++++++++++++++++ .../java/com/horcrux/svg/RenderableView.java | 22 +++++++ .../horcrux/svg/RenderableViewManager.java | 5 ++ .../main/java/com/horcrux/svg/SVGLength.java | 11 +++- .../RNSVGCircleManagerDelegate.java | 6 +- .../RNSVGCircleManagerInterface.java | 1 + .../RNSVGClipPathManagerDelegate.java | 6 +- .../RNSVGClipPathManagerInterface.java | 1 + .../RNSVGEllipseManagerDelegate.java | 6 +- .../RNSVGEllipseManagerInterface.java | 1 + .../RNSVGForeignObjectManagerDelegate.java | 6 +- .../RNSVGForeignObjectManagerInterface.java | 1 + .../RNSVGGroupManagerDelegate.java | 6 +- .../RNSVGGroupManagerInterface.java | 1 + .../RNSVGImageManagerDelegate.java | 6 +- .../RNSVGImageManagerInterface.java | 1 + .../RNSVGLineManagerDelegate.java | 6 +- .../RNSVGLineManagerInterface.java | 1 + .../RNSVGMarkerManagerDelegate.java | 6 +- .../RNSVGMarkerManagerInterface.java | 1 + .../RNSVGMaskManagerDelegate.java | 6 +- .../RNSVGMaskManagerInterface.java | 1 + .../RNSVGPathManagerDelegate.java | 6 +- .../RNSVGPathManagerInterface.java | 1 + .../RNSVGPatternManagerDelegate.java | 6 +- .../RNSVGPatternManagerInterface.java | 1 + .../RNSVGRectManagerDelegate.java | 6 +- .../RNSVGRectManagerInterface.java | 1 + .../RNSVGSymbolManagerDelegate.java | 6 +- .../RNSVGSymbolManagerInterface.java | 1 + .../RNSVGTSpanManagerDelegate.java | 6 +- .../RNSVGTSpanManagerInterface.java | 1 + .../RNSVGTextManagerDelegate.java | 6 +- .../RNSVGTextManagerInterface.java | 1 + .../RNSVGTextPathManagerDelegate.java | 6 +- .../RNSVGTextPathManagerInterface.java | 1 + .../viewmanagers/RNSVGUseManagerDelegate.java | 6 +- .../RNSVGUseManagerInterface.java | 1 + apple/Utils/RCTConvert+RNSVG.mm | 16 ++++- 40 files changed, 219 insertions(+), 23 deletions(-) create mode 100644 TestsExample/src/Test2089.tsx diff --git a/TestsExample/App.js b/TestsExample/App.js index dd4319de..023cd38f 100644 --- a/TestsExample/App.js +++ b/TestsExample/App.js @@ -9,7 +9,8 @@ import Test1845 from './src/Test1845'; import Test2080 from './src/Test2080'; import PointerEventsBoxNone from './src/PointerEventsBoxNone'; import Test2071 from './src/Test2071'; +import Test2089 from './src/Test2089'; export default function App() { - return ; + return ; } diff --git a/TestsExample/src/Test2089.tsx b/TestsExample/src/Test2089.tsx new file mode 100644 index 00000000..7a5170ce --- /dev/null +++ b/TestsExample/src/Test2089.tsx @@ -0,0 +1,66 @@ +import React, {useEffect} from 'react'; +import Animated, { + useSharedValue, + withTiming, + Easing, + withRepeat, + interpolate, + useDerivedValue, + useAnimatedProps, +} from 'react-native-reanimated'; +import {Svg, Circle} from 'react-native-svg'; + +export default () => { + const AnimatedCircle = Animated.createAnimatedComponent(Circle); + const animatedValue = useSharedValue(0); + const timingAnimatedValue = useDerivedValue(() => + withRepeat( + withTiming(animatedValue.value, { + duration: 1250, + easing: Easing.out(Easing.cubic), + }), + -1, + ), + ); + const animatedProps = useAnimatedProps(() => ({ + strokeDasharray: [ + interpolate( + timingAnimatedValue.value, + [0, 50, 100], + [8.1681408993, 40.8407044967, 8.1681408993], + ), + interpolate( + timingAnimatedValue.value, + [0, 50, 100], + [73.513268094, 40.8407045967, 73.513268094], + ), + ], + })); + + useEffect(() => { + animatedValue.value = 100; + }, []); + + return ( + + + + + + ); +}; diff --git a/android/src/main/java/com/horcrux/svg/RenderableView.java b/android/src/main/java/com/horcrux/svg/RenderableView.java index 0002ab79..e5e485f4 100644 --- a/android/src/main/java/com/horcrux/svg/RenderableView.java +++ b/android/src/main/java/com/horcrux/svg/RenderableView.java @@ -266,6 +266,28 @@ public abstract class RenderableView extends VirtualView implements ReactHitSlop invalidate(); } + public void setStrokeDasharray(@Nullable String strokeDasharray) { + if (strokeDasharray != null) { + String stringValue = strokeDasharray.trim(); + stringValue = stringValue.replaceAll(",", " "); + String[] strings = stringValue.split(" "); + ArrayList list = new ArrayList<>(strings.length); + for (String length : strings) { + list.add(new SVGLength(length)); + } + this.strokeDasharray = new SVGLength[Math.max(list.size(), 2)]; + for (int i = 0; i < list.size(); i++) { + this.strokeDasharray[i] = list.get(i); + } + if (list.size() == 1) { + this.strokeDasharray[1] = this.strokeDasharray[0]; + } + } else { + this.strokeDasharray = null; + } + invalidate(); + } + public void setStrokeDashoffset(float strokeDashoffset) { this.strokeDashoffset = strokeDashoffset * mScale; invalidate(); diff --git a/android/src/main/java/com/horcrux/svg/RenderableViewManager.java b/android/src/main/java/com/horcrux/svg/RenderableViewManager.java index 6882d4a3..816de628 100644 --- a/android/src/main/java/com/horcrux/svg/RenderableViewManager.java +++ b/android/src/main/java/com/horcrux/svg/RenderableViewManager.java @@ -2043,6 +2043,11 @@ class RenderableViewManager extends VirtualViewManager node.setStrokeDasharray(strokeDasharray); } + @ReactProp(name = "strokeDasharray") + public void setStrokeDasharray(T node, @Nullable String strokeDasharray) { + node.setStrokeDasharray(strokeDasharray); + } + @ReactProp(name = "strokeDashoffset") public void setStrokeDashoffset(T node, float strokeDashoffset) { node.setStrokeDashoffset(strokeDashoffset); diff --git a/android/src/main/java/com/horcrux/svg/SVGLength.java b/android/src/main/java/com/horcrux/svg/SVGLength.java index e5830833..5fe876b2 100644 --- a/android/src/main/java/com/horcrux/svg/SVGLength.java +++ b/android/src/main/java/com/horcrux/svg/SVGLength.java @@ -33,7 +33,7 @@ class SVGLength { unit = UnitType.NUMBER; } - private SVGLength(String length) { + SVGLength(String length) { length = length.trim(); int stringLength = length.length(); int percentIndex = stringLength - 1; @@ -143,8 +143,13 @@ class SVGLength { } case String: { - ArrayList list = new ArrayList<>(1); - list.add(new SVGLength(dynamic.asString())); + String stringValue = dynamic.asString().trim(); + stringValue = stringValue.replaceAll(",", " "); + String[] strings = stringValue.split(" "); + ArrayList list = new ArrayList<>(strings.length); + for (String length : strings) { + list.add(new SVGLength(length)); + } return list; } default: diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGCircleManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGCircleManagerDelegate.java index 97aaeb74..61ccf50e 100644 --- a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGCircleManagerDelegate.java +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGCircleManagerDelegate.java @@ -90,7 +90,11 @@ public class RNSVGCircleManagerDelegate { void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDasharray(T view, @Nullable String value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGClipPathManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGClipPathManagerDelegate.java index f79436f0..8b8dd491 100644 --- a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGClipPathManagerDelegate.java +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGClipPathManagerDelegate.java @@ -90,7 +90,11 @@ public class RNSVGClipPathManagerDelegate { void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDasharray(T view, @Nullable String value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGEllipseManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGEllipseManagerDelegate.java index 436d4d70..4a9a216f 100644 --- a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGEllipseManagerDelegate.java +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGEllipseManagerDelegate.java @@ -90,7 +90,11 @@ public class RNSVGEllipseManagerDelegate { void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDasharray(T view, @Nullable String value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGForeignObjectManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGForeignObjectManagerDelegate.java index 9ab82c2b..77c1eb55 100644 --- a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGForeignObjectManagerDelegate.java +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGForeignObjectManagerDelegate.java @@ -90,7 +90,11 @@ public class RNSVGForeignObjectManagerDelegate { void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDasharray(T view, @Nullable String value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGGroupManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGGroupManagerDelegate.java index 4f3ef867..2b577350 100644 --- a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGGroupManagerDelegate.java +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGGroupManagerDelegate.java @@ -90,7 +90,11 @@ public class RNSVGGroupManagerDelegate { void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDasharray(T view, @Nullable String value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGImageManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGImageManagerDelegate.java index 67eb24bd..eb6729fe 100644 --- a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGImageManagerDelegate.java +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGImageManagerDelegate.java @@ -90,7 +90,11 @@ public class RNSVGImageManagerDelegate { void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDasharray(T view, @Nullable String value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGLineManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGLineManagerDelegate.java index a11172d2..dcc8e3c0 100644 --- a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGLineManagerDelegate.java +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGLineManagerDelegate.java @@ -90,7 +90,11 @@ public class RNSVGLineManagerDelegate { void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDasharray(T view, @Nullable String value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGMarkerManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGMarkerManagerDelegate.java index c918b781..db7d47bb 100644 --- a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGMarkerManagerDelegate.java +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGMarkerManagerDelegate.java @@ -90,7 +90,11 @@ public class RNSVGMarkerManagerDelegate { void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDasharray(T view, @Nullable String value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGMaskManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGMaskManagerDelegate.java index 8730b0a1..456ab0e8 100644 --- a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGMaskManagerDelegate.java +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGMaskManagerDelegate.java @@ -90,7 +90,11 @@ public class RNSVGMaskManagerDelegate { void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDasharray(T view, @Nullable String value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGPathManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGPathManagerDelegate.java index 2d15a930..e0e2179a 100644 --- a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGPathManagerDelegate.java +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGPathManagerDelegate.java @@ -90,7 +90,11 @@ public class RNSVGPathManagerDelegate { void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDasharray(T view, @Nullable String value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGPatternManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGPatternManagerDelegate.java index 62e4cc00..054d1efc 100644 --- a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGPatternManagerDelegate.java +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGPatternManagerDelegate.java @@ -90,7 +90,11 @@ public class RNSVGPatternManagerDelegate { void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDasharray(T view, @Nullable String value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGRectManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGRectManagerDelegate.java index bcaac92d..8dbb9830 100644 --- a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGRectManagerDelegate.java +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGRectManagerDelegate.java @@ -90,7 +90,11 @@ public class RNSVGRectManagerDelegate { void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDasharray(T view, @Nullable String value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGSymbolManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGSymbolManagerDelegate.java index eb611e02..6ae4acf3 100644 --- a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGSymbolManagerDelegate.java +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGSymbolManagerDelegate.java @@ -90,7 +90,11 @@ public class RNSVGSymbolManagerDelegate { void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDasharray(T view, @Nullable String value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGTSpanManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGTSpanManagerDelegate.java index 0134c9de..cb189572 100644 --- a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGTSpanManagerDelegate.java +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGTSpanManagerDelegate.java @@ -90,7 +90,11 @@ public class RNSVGTSpanManagerDelegate { void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDasharray(T view, @Nullable String value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGTextManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGTextManagerDelegate.java index 0801461b..eb741608 100644 --- a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGTextManagerDelegate.java +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGTextManagerDelegate.java @@ -90,7 +90,11 @@ public class RNSVGTextManagerDelegate { void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDasharray(T view, @Nullable String value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGTextPathManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGTextPathManagerDelegate.java index a7440719..64f3ce1f 100644 --- a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGTextPathManagerDelegate.java +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGTextPathManagerDelegate.java @@ -90,7 +90,11 @@ public class RNSVGTextPathManagerDelegate { void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDasharray(T view, @Nullable String value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGUseManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGUseManagerDelegate.java index 0bc8e058..65c70f4d 100644 --- a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGUseManagerDelegate.java +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGUseManagerDelegate.java @@ -90,7 +90,11 @@ public class RNSVGUseManagerDelegate { void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, @Nullable ReadableArray value); + void setStrokeDasharray(T view, @Nullable String value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); diff --git a/apple/Utils/RCTConvert+RNSVG.mm b/apple/Utils/RCTConvert+RNSVG.mm index c0c863c9..91abfb9f 100644 --- a/apple/Utils/RCTConvert+RNSVG.mm +++ b/apple/Utils/RCTConvert+RNSVG.mm @@ -128,8 +128,20 @@ RCT_ENUM_CONVERTER( return lengths; } else if ([json isKindOfClass:[NSString class]]) { NSString *stringValue = (NSString *)json; - RNSVGLength *length = [RNSVGLength lengthWithString:stringValue]; - return [NSArray arrayWithObject:length]; + stringValue = [stringValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + stringValue = [stringValue stringByReplacingOccurrencesOfString:@"," + withString:@" " + options:NSRegularExpressionSearch + range:NSMakeRange(0, stringValue.length)]; + NSArray *array = [stringValue componentsSeparatedByString:@" "]; + NSMutableArray *svgLengthArray = [NSMutableArray array]; + + for (NSString *string in array) { + RNSVGLength *length = [RNSVGLength lengthWithString:string]; + [svgLengthArray addObject:length]; + } + + return svgLengthArray; } else { return nil; }