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

React Native中椭圆/圆角矩形视图的进度边框实现问题

为非圆形视图添加进度指示器边框(React Native)

我正在开发一个React Native项目,需要给非圆形视图(比如椭圆、圆角矩形)添加进度指示器边框。之前用react-native-svg的Circle组件实现了圆形进度指示器,但不符合需求。

目标效果

目标效果

当前效果

当前效果

现有简化代码

import { TouchableOpacity, Text, View, StyleSheet } from 'react-native';
import moment from 'moment';
import Svg, { Circle } from 'react-native-svg';

const DateComponent = () => {
  const date = moment(new Date());
  const dayName = date.format('dd').charAt(0);
  const dayNumber = date.format('D');
  const isFutureDate = date.isAfter(moment(), 'day');

  const progress = 0.75;
  const radius = 35;
  const strokeWidth = 2;
  const circumference = 2 * Math.PI * radius;

  return (
    <TouchableOpacity  style={styles.container}>
      <View style={styles.wrapper}>
        <Svg height="70" width="70" viewBox="0 0 70 70">
          <Circle
            cx="35" 
            cy="35"
            r={radius}
            stroke="gray"
            strokeWidth={strokeWidth}
            fill="none"
            opacity={0.2}
          />
          <Circle
            cx="35"
            cy="35"
            r={radius}
            stroke="green"
            strokeWidth={strokeWidth}
            fill="none"
            strokeDasharray={`${circumference} ${circumference}`}
            strokeDashoffset={(1 - progress) * circumference}
            strokeLinecap="round"
            transform="rotate(-90, 35, 35)"
          />
        </Svg>

        <View style={styles.card}>
          <Text style={styles.dayText}>{dayName}</Text>
          <Text style={[styles.dateText, { color: isFutureDate ? '#757575' : 'black' }]}>
            {dayNumber}
          </Text>
        </View>
      </View>
    </TouchableOpacity>
  );
};

const styles = StyleSheet.create({
  container: {
    justifyContent: 'center',
    alignItems: 'center',
  },
  wrapper: {
    justifyContent: 'center',
    alignItems: 'center',
  },
  card: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    justifyContent: 'center',
    alignItems: 'center',
    borderRadius: 35,
    height: 70,
    width: 70,
  },
  dayText: {
    fontSize: 14,
    color: '#757575',
  },
  dateText: {
    fontSize: 18,
    fontWeight: 'bold',
  },
});

export default DateComponent;

解决方案:用react-native-svg的Path组件绘制自定义进度边框

对于圆角矩形、椭圆这类非圆形视图,核心思路是用Path定义完整的形状轮廓,再通过strokeDasharray和strokeDashoffset实现进度截断效果。

适配圆角矩形的示例代码

import { TouchableOpacity, Text, View, StyleSheet } from 'react-native';
import moment from 'moment';
import Svg, { Path } from 'react-native-svg';

const DateComponent = () => {
  const date = moment(new Date());
  const dayName = date.format('dd').charAt(0);
  const dayNumber = date.format('D');
  const isFutureDate = date.isAfter(moment(), 'day');

  const progress = 0.75;
  const strokeWidth = 2;
  // 自定义圆角矩形尺寸:宽70,高70,圆角半径35(可根据需求调整)
  const width = 70;
  const height = 70;
  const borderRadius = 35;
  // 计算路径总长度(手动近似值,也可通过ref动态获取精确值)
  const pathTotalLength = 2 * (width + height - 2 * borderRadius) + 2 * Math.PI * borderRadius;
  const dashOffset = (1 - progress) * pathTotalLength;

  // 圆角矩形的SVG路径指令:M=移动起点,L=直线,A=圆弧
  const rectPath = `M ${borderRadius} 0 
                   L ${width - borderRadius} 0 
                   A ${borderRadius} ${borderRadius} 0 0 1 ${width} ${borderRadius} 
                   L ${width} ${height - borderRadius} 
                   A ${borderRadius} ${borderRadius} 0 0 1 ${width - borderRadius} ${height} 
                   L ${borderRadius} ${height} 
                   A ${borderRadius} ${borderRadius} 0 0 1 0 ${height - borderRadius} 
                   L 0 ${borderRadius} 
                   A ${borderRadius} ${borderRadius} 0 0 1 ${borderRadius} 0`;

  return (
    <TouchableOpacity style={styles.container}>
      <View style={styles.wrapper}>
        <Svg height={height} width={width} viewBox={`0 0 ${width} ${height}`}>
          {/* 灰色背景边框 */}
          <Path
            d={rectPath}
            stroke="gray"
            strokeWidth={strokeWidth}
            fill="none"
            opacity={0.2}
          />
          {/* 绿色进度边框 */}
          <Path
            d={rectPath}
            stroke="green"
            strokeWidth={strokeWidth}
            fill="none"
            strokeDasharray={`${pathTotalLength} ${pathTotalLength}`}
            strokeDashoffset={dashOffset}
            strokeLinecap="round"
            transform="rotate(-90, 35, 35)" // 旋转后进度从顶部开始
          />
        </Svg>

        <View style={styles.card}>
          <Text style={styles.dayText}>{dayName}</Text>
          <Text style={[styles.dateText, { color: isFutureDate ? '#757575' : 'black' }]}>
            {dayNumber}
          </Text>
        </View>
      </View>
    </TouchableOpacity>
  );
};

const styles = StyleSheet.create({
  container: {
    justifyContent: 'center',
    alignItems: 'center',
  },
  wrapper: {
    justifyContent: 'center',
    alignItems: 'center',
  },
  card: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    justifyContent: 'center',
    alignItems: 'center',
    borderRadius: 35,
    height: 70,
    width: 70,
  },
  dayText: {
    fontSize: 14,
    color: '#757575',
  },
  dateText: {
    fontSize: 18,
    fontWeight: 'bold',
  },
});

export default DateComponent;

关键说明

  1. Path路径定义:用SVG路径指令绘制闭合的自定义形状,圆角矩形用A指令绘制圆弧,椭圆则调整A指令的rx、ry参数(分别对应椭圆的x、y半轴)。
  2. 进度控制逻辑:和圆形进度条一致,通过strokeDasharray设置路径总长度,strokeDashoffset控制进度截断位置,strokeLinecap="round"保证进度两端圆润。
  3. 精确长度获取:如果需要更精确的路径长度,可以给Path添加ref,在组件挂载后调用ref.current.getTotalLength()获取实际长度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 09:35:00