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 point this.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}> <AnimatedCircularProgress size={200} width={3} backgroundWidth={30} fill={fill} tintColor="#00e0ff" backgroundColor="#3d5875" > {fill => <Text style={styles.points}>{Math.round((MAX_POINTS * fill) / 100)}</Text>} </AnimatedCircularProgress> <AnimatedCircularProgress size={120} width={15} backgroundWidth={5} fill={fill} tintColor="#00ff00" tintColorSecondary="#ff0000" backgroundColor="#3d5875" arcSweepAngle={240} rotation={240} lineCap="round" /> <AnimatedCircularProgress size={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