DEV Community

Vikas Kumar
Vikas Kumar

Posted on • Originally published at geekyhub.in on

Animate SVG in React Native

Here, by animating SVG, I mean to change the property of SVG elements dynamically, which will look live-like.

In react native, we can generate/render an SVG using the react-native-svg library. A complex SVG comprises many more minor elements that could be animated individually. But here, for example, we will take only one piece, a circle.

The following code will draw a circle with a radius of 50 units.

<Svg width={200} height={200}>
  <Circle cx="55" cy="55" r="50" stroke="black" strokeWidth={5} />
</Svg>

Enter fullscreen mode Exit fullscreen mode

Suppose we want to animate it to become large and small. To achieve this, I will use React Native Reanimated. To learn more about it, you can check out its documentation.

Logically, I am trying to increase or decrease the radius.

Since the radius value is a prop, I will use useAnimatedProps. But, first of all, convert Circle to an animated component.

const AnimatedCircle = Animated.createAnimatedComponent(Circle);

Enter fullscreen mode Exit fullscreen mode

Now, I can re-write component as

<Svg width={200} height={200}>
  <AnimatedCircle cx="55" cy="55" r="50" stroke="black" strokeWidth={5} />
</Svg>

Enter fullscreen mode Exit fullscreen mode

Next step is to store the stroke width and radius. width can be stored in a simple constat, but for the radius we will use useSharedValue, so that it can be used by woklet to animate.

export default ()=>{
  const radius = useSharedValue(50);
  const strokeWidth = 5;

  return (
    <Svg width={200} height={200}>
      <AnimatedCircle
        cx={`${radius.value + strokeWidth}`}
        cy={`${radius.value + strokeWidth}`}
        r={`${radius.value}`}
        stroke="black"
        strokeWidth={strokeWidth}
      />
    </Svg>
  )
}

Enter fullscreen mode Exit fullscreen mode

Here, I need some event or action to trigger the radius change. Iโ€™ll use a button press. (withSpring is default provided animation which is not necessary to use but this looks cool ๐Ÿคž)

<Button mode="contained" onPress={() => {
  if(radius.value < 80) {
  radius.value = withSpring(80)
  }else{
    radius.value = withSpring(50)
  }
}}>
  Press
</Button>

Enter fullscreen mode Exit fullscreen mode

Youโ€™ll notice that even after pressing the button, nothing happens. It is because change of sharedValue doesnโ€™t trigger re-render of the react component. finally animated props comes into the picture. Instead of passing prop directly, we will pass it using animated prop.

const animatedProps = useAnimatedProps(() => ({
  cx: `${radius.value + strokeWidth}`,
  cy: `${radius.value + strokeWidth}`,
  r:`${radius.value}`
}));


<Svg width={200} height={200}>
  <AnimatedCircle
    animatedProps={animatedProps}
    stroke="black"
    strokeWidth={strokeWidth}
  />
</Svg>

Enter fullscreen mode Exit fullscreen mode

Result, is something like this.

This is a relatively simple example, but I hope I successfully demonstrated the possibilities. Here is the link of complete code of the result if you are interested.

Top comments (0)