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

使用react-native-svg实现分段环形进度条出现显示异常求助

修复自定义分段环形进度条问题

核心问题定位

你的代码大概率没有正确累加每个分段的起始角度,导致所有分段都从同一个初始角度绘制,互相覆盖后只留下重复显示的紫色分段,其余分段被完全遮挡。

修复后的完整组件代码

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

const SegmentedRingProgress = ({
  segments, // 数据格式:[{ value: 数值, color: 颜色 }, ...]
  radius = 100,
  strokeWidth = 20,
  startAngle = -90, // 起始角度(-90对应环形顶部)
}) => {
  const totalValue = segments.reduce((sum, seg) => sum + seg.value, 0);
  const centerX = radius + strokeWidth / 2;
  const centerY = radius + strokeWidth / 2;
  const outerRadius = radius;
  const innerRadius = radius - strokeWidth;

  // 角度转弧度工具函数
  const degToRad = (deg) => (deg * Math.PI) / 180;

  // 生成单个分段的环形路径
  const getArcPath = (startDeg, endDeg, isLargeArc) => {
    const startRad = degToRad(startDeg);
    const endRad = degToRad(endDeg);

    // 外弧起止点坐标
    const startX = centerX + outerRadius * Math.cos(startRad);
    const startY = centerY + outerRadius * Math.sin(startRad);
    const endX = centerX + outerRadius * Math.cos(endRad);
    const endY = centerY + outerRadius * Math.sin(endRad);

    // 内弧起止点坐标
    const innerStartX = centerX + innerRadius * Math.cos(startRad);
    const innerStartY = centerY + innerRadius * Math.sin(startRad);
    const innerEndX = centerX + innerRadius * Math.cos(endRad);
    const innerEndY = centerY + innerRadius * Math.sin(endRad);

    // 拼接SVG路径命令:外弧→内弧→闭合路径
    return `
      M ${startX} ${startY}
      A ${outerRadius} ${outerRadius} 0 ${isLargeArc ? 1 : 0} 1 ${endX} ${endY}
      L ${innerEndX} ${innerEndY}
      A ${innerRadius} ${innerRadius} 0 ${isLargeArc ? 1 : 0} 0 ${innerStartX} ${innerStartY}
      Z
    `;
  };

  let currentAngle = startAngle;

  return (
    <View>
      <Svg
        width={radius * 2 + strokeWidth}
        height={radius * 2 + strokeWidth}
      >
        {segments.map((segment, index) => {
          // 计算当前分段占总环形的角度
          const segmentAngle = (segment.value / totalValue) * 360;
          const endAngle = currentAngle + segmentAngle;
          // 处理大于180度的分段,确保SVG路径绘制正确
          const isLargeArc = segmentAngle > 180 ? 1 : 0;

          const path = getArcPath(currentAngle, endAngle, isLargeArc);
          // 更新下一个分段的起始角度
          currentAngle = endAngle;

          return (
            <Path
              key={index}
              d={path}
              fill={segment.color}
            />
          );
        })}
      </Svg>
    </View>
  );
};

export default SegmentedRingProgress;

使用示例(App.js)

import SegmentedRingProgress from './SegmentedRingProgress';

// 你的分段数据示例
const ringSegments = [
  { value: 30, color: '#FF6B6B' },
  { value: 25, color: '#4ECDC4' },
  { value: 20, color: '#FFE66D' },
  { value: 25, color: '#95E1D3' },
];

// 组件调用
<SegmentedRingProgress
  segments={ringSegments}
  radius={80}
  strokeWidth={15}
  startAngle={-90}
/>

关键修复点

  1. 新增currentAngle变量,每个分段绘制完成后更新为当前分段的结束角度,确保下一个分段从正确位置开始
  2. 每个分段使用独立的闭合环形路径(外弧+内弧+闭合命令),彻底避免分段重叠遮挡
  3. 处理了大于180度的分段场景,通过isLargeArc参数保证路径绘制正确

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 11:52:20