
Vertical Step indicator
May 06, 2023
1 min

React Native component for creating animated, circular progress. Useful for displaying users points for example.
You can configure the CircularProgress-component by passing the following props:
| Name | Type | Default value | Description |
|---|---|---|---|
| size | number|Animated.Value | required | Width and height of circle |
| width | number | required | Thickness of the progress line |
| backgroundWidth | number | width | Thickness of background circle |
| fill | number (0-100) | 0 | Current progress / fill |
| tintColor | string | black | Color of the progress line |
| tintTransparency | boolean | true | Transparency of the progress line |
| backgroundColor | string | If unspecified, no background line will be rendered | |
| rotation | number (-360 - 360) | 90 | Angle from which the progress starts from |
| lineCap | string | butt | Shape used at ends of progress line. Possible values: butt, round, square |
| arcSweepAngle | number (0-360) | 360 | If you don’t want a full circle, specify the arc angle |
| style | ViewPropTypes.style | Extra styling for the main container | |
| children | function | Pass a function as a child. It received the current fill-value as an argument | |
| childrenContainerStyle | ViewPropTypes.style | Extra styling for the children container | |
| padding | number | 0 | Padding applied around the circle to allow for a cap that bleeds outside its boundary |
| dashedBackground | object | { width: 0, gap: 0 } | Bar background as dashed type |
| dashedTint | object | { width: 0, gap: 0 } | Bar tint as dashed type |
| renderCap | function | undefined | Function that’s invoked during rendering to draw at the tip of the progress circle |
The following props can further be used on AnimatedCircularProgress:
| Name | Type | Default value | Description |
|---|---|---|---|
| prefill | number (0-100) | 0 | Initial fill-value before animation starts |
| duration | number | 500 | Duration of animation in ms |
| delay | number | 0 | Delay of animation in ms |
| easing | function | Easing.out(Easing.ease) | Animation easing function |
| onAnimationComplete | function | Function that’s invoked when the animation completes (both on mount and if called with .animate()) | |
| onFillChange | function | Function that returns current progress on every change | |
| tintColorSecondary | string | the same as tintColor | To change fill color from tintColor to tintColorSecondary as animation progresses |
AnimatedCircularProgress also exposes the following functions:
| Name | Arguments | Description |
|---|---|---|
| animate | (toVal: number, duration: number, ease: function) | Animate the progress bar to a specific value |
| reAnimate | (prefill: number, toVal: number, duration: number, ease: function) | Re-run animation with a specified prefill-value |
Install this component and react-native-svg:
npm i --save react-native-circular-progress react-native-svg
Link native code for SVG:
react-native link react-native-svg
import React from 'react';import { StyleSheet, Text, PanResponder, View, PanResponderInstance } from 'react-native';import { AnimatedCircularProgress } from 'react-native-circular-progress';const MAX_POINTS = 500;export default class App extends React.Component {state = {isMoving: false,pointsDelta: 0,points: 325,};_panResponder : PanResponderInstance;_circularProgressRef: React.RefObject<AnimatedCircularProgress>;constructor(props: Readonly<{}>) {super(props);this._circularProgressRef = React.createRef();this._panResponder = PanResponder.create({onStartShouldSetPanResponder: (evt, gestureState) => true,onStartShouldSetPanResponderCapture: (evt, gestureState) => true,onMoveShouldSetPanResponder: (evt, gestureState) => true,onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,onPanResponderGrant: (evt, gestureState) => {this.setState({ isMoving: true, pointsDelta: 0 });},onPanResponderMove: (evt, gestureState) => {if (this._circularProgressRef.current) {this._circularProgressRef.current.animate(0, 0);}// For each 2 pixels add or subtract 1 pointthis.setState({ pointsDelta: Math.round(-gestureState.dy / 2) });},onPanResponderTerminationRequest: (evt, gestureState) => true,onPanResponderRelease: (evt, gestureState) => {if (this._circularProgressRef.current) {this._circularProgressRef.current.animate(100, 3000);}let points = this.state.points + this.state.pointsDelta;console.log(Math.min(points, MAX_POINTS));this.setState({isMoving: false,points: points > 0 ? Math.min(points, MAX_POINTS) : 0,pointsDelta: 0,});},});}render() {const fill = (this.state.points / MAX_POINTS) * 100;return (<View style={styles.container} {...this._panResponder.panHandlers}><AnimatedCircularProgresssize={200}width={3}backgroundWidth={30}fill={fill}tintColor="#00e0ff"backgroundColor="#3d5875">{fill => <Text style={styles.points}>{Math.round((MAX_POINTS * fill) / 100)}</Text>}</AnimatedCircularProgress><AnimatedCircularProgresssize={120}width={15}backgroundWidth={5}fill={fill}tintColor="#00ff00"tintColorSecondary="#ff0000"backgroundColor="#3d5875"arcSweepAngle={240}rotation={240}lineCap="round"/><AnimatedCircularProgresssize={100}width={25}fill={0}tintColor="#00e0ff"onAnimationComplete={() => console.log('onAnimationComplete')}ref={this._circularProgressRef}backgroundColor="#3d5875"arcSweepAngle={180}/><Text style={[styles.pointsDelta, this.state.isMoving && styles.pointsDeltaActive]}>{this.state.pointsDelta >= 0 && '+'}{this.state.pointsDelta}</Text></View>);}}const styles = StyleSheet.create({points: {textAlign: 'center',color: '#7591af',fontSize: 50,fontWeight: '100',},container: {flex: 1,justifyContent: 'space-between',alignItems: 'center',backgroundColor: '#152d44',padding: 50,},pointsDelta: {color: '#4c6479',fontSize: 50,fontWeight: '100',},pointsDeltaActive: {color: '#fff',},});
Coming Soon…






Quick Links
Legal Stuff