如何在 Expo React Native 中创建一个中心有文本的圆形进度条?

问题描述 投票:0回答:1

我是 React Native 新手,正在尝试创建以下屏幕:

CircularProgressBar

我尝试使用两种方法:

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;

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;

在这两种情况下都会重叠

CircularProgressBar
,将其完全隐藏。

有什么建议吗?

react-native expo
1个回答
0
投票

确保您的项目中已安装

react-native-svg

npm install react-native-svg

然后尝试运行以下代码,该代码基于您上面的示例

   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;
© www.soinside.com 2019 - 2024. All rights reserved.