Here, by animating an SVG, I mean changing the properties of SVG elements dynamically to make them appear alive.

In React Native, we can generate or render an SVG using the react-native-svg library. A complex SVG comprises many smaller elements that can be animated individually. For this example, however, we will use only one element: 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>

Suppose we want to animate it so that it grows and shrinks. 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. First, convert Circle to an animated component.

const AnimatedCircle = Animated.createAnimatedComponent(Circle);

Now I can rewrite the component as follows:

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

The next step is to store the stroke width and radius. The width can be stored in a simple constant, but for the radius we will use useSharedValue so that a worklet can animate it.

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>
  )
}

Here, I need an event or action to trigger the radius change. I’ll use a button press. (withSpring is a provided animation that isn’t required, but it looks cool 🤞.)

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

You’ll notice that even after pressing the button, nothing happens. This is because changing a shared value doesn’t trigger a re-render of the React component. Finally, animated props come into the picture. Instead of passing the props directly, we will pass them using animatedProps.

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>

The result looks something like this:

This is a relatively simple example, but I hope I successfully demonstrated the possibilities. If you are interested, here is the complete code for the result.