skip to Main Content

I am new to React Native and trying to create the following screen:

CircularProgressBar

I try to use two approaches:

import React, { useState, useEffect } from 'react';
import { View, StyleSheet, Text } from 'react-native';
import Svg, { Circle, Text as SvgText } from 'react-native-svg';

interface ProgressCircleProps {
  radius: number;
  strokeWidth: number;
  progress: number; // Should be a value between 0 and 1
  color: string;
}

const ProgressCircle: React.FC<ProgressCircleProps> = ({
  radius,
  strokeWidth,
  progress,
  color,
}) => {
  const [circumference, setCircumference] = useState(0);

  useEffect(() => {
    const circumferenceValue = 2 * Math.PI * radius;
    setCircumference(circumferenceValue);
  }, [radius]);

  const strokeDashoffset = circumference * (1 - progress);
  const progressPercentage = `${Math.round(progress * 100)}%`;

  return (
    <View style={{ aspectRatio: 1, width: radius * 2 }}>
      <Svg width={radius * 2} height={radius * 2}>
        <Circle
          stroke={color}
          fill="transparent"
          strokeWidth={strokeWidth}
          strokeDasharray={circumference}
          strokeDashoffset={strokeDashoffset}
          cx={radius}
          cy={radius}
          r={radius - strokeWidth / 2}
        />
        <SvgText
          x="50%"
          y="50%"
          textAnchor="middle"
          alignmentBaseline="middle"
          fontSize={radius / 2.5}
          fill="#333" // Adjust text color as needed
          fontWeight="bold"
        >
          {progressPercentage}
        </SvgText>
      </Svg>
    </View>
  );
};

export default ProgressCircle;

and

import React, { useState, useEffect } from 'react';
import { View } from 'react-native';
import Svg, { Circle } from 'react-native-svg';

interface ProgressCircleProps {
  radius: number;
  strokeWidth: number;
  progress: number; // Should be a value between 0 and 1
  color: string;
}

const ProgressCircle: React.FC<ProgressCircleProps> = ({
  radius,
  strokeWidth,
  progress,
  color,
}) => {
  const [circumference, setCircumference] = useState(0);

  useEffect(() => {
    const circumferenceValue = 2 * Math.PI * radius;
    setCircumference(circumferenceValue);
  }, [radius]);

  const strokeDashoffset = circumference * (1 - progress);

  return (
    <View style={{ aspectRatio: 1, width: radius * 2 }}>
      <Svg width={radius * 2} height={radius * 2}>
        <Circle
          stroke={color}
          fill="transparent"
          strokeWidth={strokeWidth}
          strokeDasharray={`${circumference} ${circumference}`}
          strokeDashoffset={strokeDashoffset}
          cx={radius}
          cy={radius}
          r={radius - strokeWidth / 2}
        />
      </Svg>
    </View>
  );
};

export default ProgressCircle;

In both situations overlaps the CircularProgressBar, hiding it completely.

Any suggestions?

2

Answers


  1. Make sure you have react-native-svg installed in your project.

    npm install react-native-svg
    

    And then try running the following code, the code is based on your example above

       import React, { useState, useEffect } from 'react';
        import { View, StyleSheet, Text } from 'react-native';
        import Svg, { Circle, Text as SvgText } from 'react-native-svg';
        
        interface ProgressCircleProps {
          radius: number;
          strokeWidth: number;
          progress: number; // Should be a value between 0 and 1
          color: string;
        }
        
        const ProgressCircle: React.FC<ProgressCircleProps> = ({
          radius,
          strokeWidth,
          progress,
          color,
        }) => {
          const [circumference, setCircumference] = useState(0);
        
          useEffect(() => {
            const circumferenceValue = 2 * Math.PI * radius;
            setCircumference(circumferenceValue);
          }, [radius]);
        
          const strokeDashoffset = circumference * (1 - progress);
          const progressValue = Math.round(progress * 2000); // Assuming progress is between 0 and 1 and total is 2000
        
          return (
            <View style={{ aspectRatio: 1, width: radius * 2 }}>
              <Svg width={radius * 2} height={radius * 2}>
                <Circle
                  stroke={color}
                  fill="transparent"
                  strokeWidth={strokeWidth}
                  strokeDasharray={circumference}
                  strokeDashoffset={strokeDashoffset}
                  cx={radius}
                  cy={radius}
                  r={radius - strokeWidth / 2}
                />
                <SvgText
                  x="50%"
                  y="50%"
                  textAnchor="middle"
                  alignmentBaseline="middle"
                  fontSize={radius / 2.5}
                  fill={color}
                  fontWeight="bold"
                >
                  {progressValue}
                </SvgText>
              </Svg>
            </View>
          );
        };
        
        export default ProgressCircle;
        
        // Usage example
        const App = () => {
          const [progress, setProgress] = useState(0.96); // Example progress value (1923/2000)
        
          return (
            <View style={styles.container}>
              <Text style={styles.header}>2000 contatos</Text>
              <ProgressCircle
                radius={100}
                strokeWidth={10}
                progress={progress}
                color="blue"
              />
              <View style={styles.button}>
                <Text style={styles.buttonText}>⟳</Text>
              </View>
            </View>
          );
        };
        
        const styles = StyleSheet.create({
          container: {
            flex: 1,
            justifyContent: 'center',
            alignItems: 'center',
          },
          header: {
            fontSize: 20,
            fontWeight: 'bold',
            marginBottom: 20,
          },
          button: {
            marginTop: 40,
            padding: 10,
            backgroundColor: 'blue',
            borderRadius: 5,
          },
          buttonText: {
            color: 'white',
            fontSize: 20,
            textAlign: 'center',
          },
        });
        
        export default App;
    
    Login or Signup to reply.
  2. You can try to use this package: react-native-circular-progress-indicator.

    However, if this package does not meet your requirements, you can definitely create a custom animated circular progress bar using react-native-svg and react-native-reanimated. This approach will require you to learn how SVG works in React Native and how to apply animations to SVG using react-native-reanimated.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search