React Native and Reanimated 2 : Progress Bars

Alaa Chakroun
eDonec
Published in
4 min readApr 12, 2021

More Reanimated 2 goodness

Photo by Mike van den Bos on Unsplash

Progress bars are an essential part of creating a user friendly mobile experience, either to show the exact progress of an action, or to provide the user a feedback showing that an action is taking place and should be resolved in due time. More often than not, we can just rely on third party libraries to provide this functionality but this comes at the cost of customization, poor performance or large bundle size, so why not build our own progress bar that we can tune to our own liking ?

Final result :

Perquisites :

react-native (0.63 or higher)

react-native-reanimated (v2.0 or higher)

react-native-redash (incredible reanimated helper library)

tinycolor2 (tiny color shading library)

The progress bars :

In this article, we are going to create 2 types of progress bars, the first one is a Determinate Progress Bar which accepts a progress number (between 0 and 1) that we can use for download and/or upload progress. The second won’t accept any props, and will be used for any indeterminate loading action such as waiting for data fetching from an API.

Both progress bars will share the same building blocks :

  • An outer container View representing the full empty bar.
  • An inner progress View representing the progress value.

Determinate Progress Bar :

Our goal in this section is to simply animate our progress view according to the progress prop value updates. We can start by accepting a progress prop, changing our inner View to an Animated.View from reanimated 2 and moving our style to an animatedStyle using the useAnimatedStyle hook.

Note : we used the tinycolor2 color library to get a lighter shade of the color to use as a background color for our progress bar.

We can now proceed to animating the width of our animating view depending on the progress prop value by declaring a reanimated shared value representing the width and animate it using a spring animation.

But when running our code we can observe this annoying bug:

This is explained by our progressWidth value springing to a negative value so react ignores the width style property. This is easily fixed by clamping our progressWidth to 0 as a lower bound and device width as a higher bound.

To do so we can create our own helper function but in this case, I recommend installing the react-native-redash helper library that provides almost all the helper functions that we need while dealing with reanimated values.

And this is our final result :

Indeterminate Progress Bar :

Starting from the same building blocks, our goal in this section is to translate the fixed width progress view along the X axis.

Which results in this following effect:

Next up, we need our animation to loop indefinitely with a small delay between each iteration. To achieve this, we can make use of the powerful High order animations concept in reanimated 2 where animations take other animations as parameters.

Finally we can tweak the timing function a bit using bezier curves using the online tool cubic-bezier.com

We can always customize our curve to get it to feel just right.

We set then the chosen function as the easing function of the timing animation.

As a result, we achieved this nice “halt” effect :

Bonus : Color interpolation

Using the withTiming callback argument, we can add some logic to interpolate the color of the progress bar on each iteration. To do so, we have to make some fundamental changes to our components.

  • Changing our container View to an Animated.View
  • We no longer accept a string color prop but instead, an array of colors (and change the naming from color to colors)
  • Removing our memoized background and foreground constants.
  • Moving all color related animation to the animated styles.
  • Creating a currentColorIndex shared value that indicates the current color and used for the necessary color interpolation.
  • Creating a reverseOrder boolean shared value to indicate the direction of the color progression.

And this is the final result :

Conclusion :

Creating our own progress bar was a fun experience that allowed us to practice and improve our reanimated 2 knowledge, in addition to allowing us to customize this component to our likings and keeping our bundle size to a minimum by not using external libraries.

This has been developed by myself at eDonec.

--

--