Animating Progress Rings with React Native Reanimated 2

Tanner West
React Native Rocket
5 min readJul 5, 2022
Three progress rings: 5%, 40%, and 90%

Reanimated 2 and React Native SVG can be combined to make some powerful and impressive animations. One of the most practical shapes to animate is circles because they can be animated to create all types of useful UI components like progress rings. Once you understand a couple of SVG fundamentals, it’s a breeze to create any animated progress ring you can dream up.

An animated progress ring that goes from 0 to 100 percent and changes color from red to yellow to green

The fundamentals: strokeDasharray and strokeDashoffset

The technique we’ll use to animate our circles depends on a neat hack using two common SVG properties: strokeDasharray and strokeDashoffset Here’s what they do.

strokeDasharray lets us create a dashed stroke around the outside of our circle, rather than a solid stoke. If we provide just one number, we’ll get a dashed stroke with dashes and gaps that are the same size.

A circle with a dashed outline

Alternatively, we can pass two numbers — the first will define the length of the dash, and the second will define the length of the gap between dashes.

A circle with a dashed outline

strokeDashoffset lets us offset the position of our stroke by a given number.

A circle with a dashed outline

How do these two properties help us animate a circle? This is where it’s time to get creative. Let’s see what happens when we set our stroke dash size to be the entire circumference of our circle (using radius * PI * 2). We end up with what looks like a solid stroke. Technically our stroke is still dashed, but our dash covers the entire circumference of the circle, so we don’t see a gap.

A circle with a solid outline

Now, let’s add an offset that’s also the size of the circumference. It looks like our stroke is gone, but what’s actually happened is that our stroke gap covers the entire circumference of the circle, since our stroke gap is also the full circumference of the circle. This makes it so we don’t see any stroke.

A circle with no outline

We can subtract any arbitrary amount from our offset to “reveal” that much of our stroke. We’ll subtract 40 and see what happens.

A circle with a partial solid outline

Do you see where this is going? 😏

Time to Animate!

To get the progress ring effect we’re after, we just need to animate strokeDashoffset from the circle’s full circumference to zero. This is pretty straightforward with Reanimated 2.

A circle with an animated outline

There are a few things to understand here.

  • We create a new component called AnimatedCircle by passing React Native SVG’s Circle through Reanimated’s createAnimatedComponent . This will allow us to animate the component’s props using Reanimated
  • We create a shared value for stroke offset, initially set to the circumference of the circle so our stroke isn’t visible
  • With useAnimatedProps , we define a withTiming animation to handle changes in the strokeDashoffset value
  • With the useEffect hook, we update our shared value of zero, thus kicking off our progress ring animation

It’s that simple to create beautiful progress ring animations with Reanimated and React Native. Of course, progress rings are usually accompanied by a numeric indicator, often expressed as a percentage. We can animate that, too!

Animating percentage text

We can apply many of the same principles we used to animate our circle and use them to animate our percentage text.

An animated progress ring that goes from 0 to 100 percent

Here’s what we’ve added:

  • We create a new component called AnimatedText by passing React Native’s TextInput through Reanimated’s createAnimatedComponent . This will allow us to animate the component’s props with Reanimated
  • We create a shared value called percentage that converts the stroke offset value to a number between 0 and 100, to track the animation’s progress
  • With useAnimatedProps , we create an animated text prop that we can pass to our AnimatedText component

Now you have a silky smooth progress ring with animated percentage text!

What’s that you say? You want to animate the color of the progress ring from red to yellow to green as it moves from 0 to 100% percent? OK, we can do that easily with Reanimated.

Animating the progress ring color

We can add the color animation we want with just a few more lines of code, thanks to Reanimated’s interpolateColor

An animated progress ring that goes from 0 to 100 percent and changes color from red to yellow to green

Here we create a new strokeColor value with useDerivedValue . To get it, we use interpolateColor to map our percentage value to the colors we want to animate. After that, we add our stroke color value to our animatedCircleProps and that’s it!

Conclusion

I hope this post has given you the knowledge to start creating your own progress rings and other animated circle components with Reanimated. I’d love to see what you build; tag me on twitter @useRNRocket! As always, comments and corrections are welcome! Follow me here and on Twitter for more React Native and Reanimated content.

--

--