You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用React与React Native实现自定义圆形进度条

你现有的两个坐标转换、弧线路径生成函数已经覆盖了核心计算逻辑,直接基于这两个函数封装组件即可,不需要依赖第三方包,适配Web和React Native的方案如下:

React Web 实现(基于原生SVG)

核心是用两层path分别做背景轨道和进度条,绑定props动态计算进度对应的弧长:

import React from 'react';

// 复用你已有的工具函数
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
  const angleInRadians = ((angleInDegrees - 90) * Math.PI) / 180.0;
  return {
    x: centerX + radius * Math.cos(angleInRadians),
    y: centerY + radius * Math.sin(angleInRadians),
  };
}

function describeArc(x, y, radius, startAngle, endAngle) {
  const start = polarToCartesian(x, y, radius, endAngle);
  const end = polarToCartesian(x, y, radius, startAngle);
  const largeArcFlag = endAngle - startAngle <= 180 ? '0' : '1';
  const d = [
    'M', start.x, start.y,
    'A', radius, radius, 0, largeArcFlag, 0, end.x, end.y
  ].join(' ');
  return d;
}

// 圆形进度条组件
const CircleProgress = ({ progress = 0, size = 200, strokeWidth = 12, bgColor = '#e5e7eb', progressColor = '#3b82f6', showText = true }) => {
  const radius = (size - strokeWidth) / 2;
  const center = size / 2;
  // 进度转角度 0-100对应0-360度
  const angle = Math.min(360, Math.max(0, (progress / 100) * 360));
  const progressPath = angle === 0 ? '' : describeArc(center, center, radius, 0, angle);

  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
      {/* 背景轨道 */}
      <path
        d={describeArc(center, center, radius, 0, 360)}
        fill="none"
        stroke={bgColor}
        strokeWidth={strokeWidth}
        strokeLinecap="round"
      />
      {/* 进度条 */}
      {angle > 0 && (
        <path
          d={progressPath}
          fill="none"
          stroke={progressColor}
          strokeWidth={strokeWidth}
          strokeLinecap="round"
        />
      )}
      {/* 中间进度文字 */}
      {showText && (
        <text x={center} y={center} textAnchor="middle" dominantBaseline="middle" fontSize={size * 0.2} fontWeight="bold" fill={progressColor}>
          {Math.round(progress)}%
        </text>
      )}
    </svg>
  );
};

export default CircleProgress;

调用时直接传参数即可:<CircleProgress progress={75} />


React Native 实现

核心逻辑和Web完全一致,只需要把SVG标签替换为react-native-svg提供的对应组件即可:

import React from 'react';
import { View, Text } from 'react-native';
import Svg, { Path } from 'react-native-svg';

// 复用你已有的两个工具函数,完全不需要修改
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
  const angleInRadians = ((angleInDegrees - 90) * Math.PI) / 180.0;
  return {
    x: centerX + radius * Math.cos(angleInRadians),
    y: centerY + radius * Math.sin(angleInRadians),
  };
}

function describeArc(x, y, radius, startAngle, endAngle) {
  const start = polarToCartesian(x, y, radius, endAngle);
  const end = polarToCartesian(x, y, radius, startAngle);
  const largeArcFlag = endAngle - startAngle <= 180 ? '0' : '1';
  const d = [
    'M', start.x, start.y,
    'A', radius, radius, 0, largeArcFlag, 0, end.x, end.y
  ].join(' ');
  return d;
}

const CircleProgress = ({ progress = 0, size = 200, strokeWidth = 12, bgColor = '#e5e7eb', progressColor = '#3b82f6', showText = true }) => {
  const radius = (size - strokeWidth) / 2;
  const center = size / 2;
  const angle = Math.min(360, Math.max(0, (progress / 100) * 360));
  const progressPath = angle === 0 ? '' : describeArc(center, center, radius, 0, angle);

  return (
    <View style={{ width: size, height: size, position: 'relative' }}>
      <Svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
        <Path
          d={describeArc(center, center, radius, 0, 360)}
          fill="none"
          stroke={bgColor}
          strokeWidth={strokeWidth}
          strokeLinecap="round"
        />
        {angle > 0 && (
          <Path
            d={progressPath}
            fill="none"
            stroke={progressColor}
            strokeWidth={strokeWidth}
            strokeLinecap="round"
          />
        )}
      </Svg>
      {showText && (
        <Text
          style={{
            position: 'absolute',
            top: 0,
            left: 0,
            width: size,
            height: size,
            textAlign: 'center',
            textAlignVertical: 'center',
            fontSize: size * 0.2,
            fontWeight: 'bold',
            color: progressColor
          }}
        >
          {Math.round(progress)}%
        </Text>
      )}
    </View>
  );
};

export default CircleProgress;

如果需要实现非整圆的缺口式圆形进度条,只需要调整describeArc传入的起始角度和最大角度即可,比如270度的仪表盘样式,设置起始角度为135,最大角度为135+270=405,进度对应角度按比例映射到135到405的区间即可。如果需要添加动画效果,直接绑定动画变量到progress属性即可。

内容的提问来源于stack exchange,提问作者AirFlight

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 20:15:02