- Published on
- ·8 min read
Creating a Progress Bar (Circle) for Displaying Progress - React Native
I apologize in advance for any awkward expressions in English.
English is not my native language, and I have relied on ChatGPT's assistance to proceed with the translation.
Overview
The "Simple Vocab Buddy" app features a Progress Circle displaying group study progress and quiz completion status. Let's explore how this was implemented.
Implemented Screen
The image below showcases the screen where the Progress Circle is applied in the current live app.
Implementation Process
❗ The example code may have omitted or simplified styles and functions for the sake of the post.
1. Install react-native-svg
As we'll be implementing the Progress Circle using SVG, let's start by installing react-native-svg
.
npm i react-native-svg
2. Create the Progress Circle Component
✨ I modified the code based on Making a progress circle in React.
The referenced code was originally written for React, so I made modifications to make it compatible with React Native and tailored it to my specific use case.
Pie.tsx
// https://dev.to/jackherizsmith/making-a-progress-circle-in-react-3o65
import Svg, {Circle, G, Text, TSpan} from 'react-native-svg';
const cleanPercentage = (percentage) => {
const tooLow = !Number.isFinite(+percentage) || percentage < 0;
const tooHigh = percentage > 100;
return tooLow ? 0 : tooHigh ? 100 : +percentage;
};
const PieCircle = ({ color, pct, radius = 50, borderWidth = 2 }:{
color: string;
pct?: number;
radius: number;
borderWidth: number;
}) => {
const circ = 2 * Math.PI * radius;
const strokePct = ((100 - pct) * circ) / 100;
return (
<Circle
r={radius}
cx={radius + borderWidth}
cy={radius + borderWidth}
fill="transparent"
fillRule={"nonzero"}
stroke={pct > 0 ? color : ""}
strokeWidth={borderWidth}
strokeDasharray={circ}
strokeDashoffset={pct ? strokePct : 0}
strokeLinecap="round"
></Circle>
);
};
const PieText = ({ percentage, title }) => {
return (
<Text
x="50%"
y="50%"
textAnchor="middle"
>
<TSpan x="50%" dy={0} fontSize={11} fontWeight={'bold'} fill={'#151A20'}>{title}</TSpan>
<TSpan x="50%" dy={14} fontSize={10} fill={'#151A20'}>{`${percentage}%`}</TSpan>
</Text>
);
};
const Pie = ({ percentage, color, title, radius = 50, borderWidth = 2}:{
percentage: number;
color: string;
title: string;
radius: number;
borderWidth: number;
}) => {
const pct = cleanPercentage(percentage);
const fullSize = (radius * 2)+(borderWidth*2);
return (
<Svg width={fullSize} height={fullSize}>
<G transform={`rotate(-90 ${radius + borderWidth} ${radius + borderWidth})`} fill={'white'}>
<Circle
r={radius}
cx={radius + borderWidth}
cy={radius + borderWidth}
fill={'#FFFFFF'}
></Circle>
<PieCircle borderWidth={borderWidth} radius={radius} color="#e3e3e3" pct={100} />
<PieCircle borderWidth={borderWidth} radius={radius} color={color} pct={pct} />
</G>
<PieText percentage={pct} title={title} />
</Svg>
);
};
export default Pie;
3. Apply the Progress Circle
- Use
<Pie ... />
tag.radius
: Specify the radius size.borderWidth
: Specify the thickness of the Progress Circle.percentage
: Specify the percentage of the Progress Circle.color
: Specify the color of the Progress Circle.title
: Specify the text for the Progress Circle.
<View>
<TouchableOpacity
accessibilityLabel={'Learning'}
onPress={() => {}}>
<Pie radius={28} borderWidth={4} percentage={getStudyRate()} color={'#4285F4'} title={'Learning'} />
</TouchableOpacity>
<View style={{width: 8}} />
<TouchableOpacity
accessibilityLabel={'Quiz'}
onPress={() => {}}>
<Pie radius={28} borderWidth={4} percentage={getQuizRate()} color={'#4285F4'} title={'Quiz'} />
</TouchableOpacity>
</View>