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

SwiftUI中如何实现小球沿圆环路径的动画效果?

实现环形进度条的跟随小圆动画

核心思路

不需要复杂的曲线动画API,核心是通过进度百分比计算对应角度,再将小圆位置映射到环形路径的坐标上,同步进度更新即可实现跟随动画。以下分两种常见场景给出实现方案:


场景1:Canvas绘制方案

假设你当前用Canvas实现环形进度条,直接在绘制逻辑中添加小圆的计算与绘制即可:

const canvas = document.getElementById('progress-canvas');
const ctx = canvas.getContext('2d');
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const ringRadius = 80;    // 进度环的半径(从圆心到环中线的距离)
const ringWidth = 10;     // 进度环的宽度
const dotRadius = 7;      // 跟随小圆的半径
let percent = 0;          // 当前进度(0~1)

function drawProgress() {
  // 清空画布
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  // 1. 绘制灰色背景环
  ctx.beginPath();
  ctx.arc(centerX, centerY, ringRadius, 0, Math.PI * 2);
  ctx.strokeStyle = '#e0e0e0';
  ctx.lineWidth = ringWidth;
  ctx.stroke();

  // 2. 绘制红色进度环(InnerRing)
  const startAngle = -Math.PI / 2; // 起始角度:顶部(Canvas默认0度为右侧,顺时针旋转)
  const endAngle = startAngle + percent * Math.PI * 2;
  ctx.beginPath();
  ctx.arc(centerX, centerY, ringRadius, startAngle, endAngle);
  ctx.strokeStyle = '#ff3333';
  ctx.lineWidth = ringWidth;
  ctx.stroke();

  // 3. 绘制跟随小圆
  // 小圆的角度与进度环的结束角度完全一致
  const dotAngle = endAngle;
  // 计算小圆的中心坐标
  const dotX = centerX + ringRadius * Math.cos(dotAngle);
  const dotY = centerY + ringRadius * Math.sin(dotAngle);
  
  ctx.beginPath();
  ctx.arc(dotX, dotY, dotRadius, 0, Math.PI * 2);
  ctx.fillStyle = '#ff3333';
  ctx.fill();

  // 驱动动画:逐步增加进度
  if (percent < 1) {
    percent += 0.008;
    requestAnimationFrame(drawProgress);
  }
}

// 启动动画
drawProgress();

关键细节

  • 起始角度用-Math.PI/2对应Canvas坐标系的顶部,确保进度从顶部开始
  • 小圆坐标直接复用进度环的结束角度,完全贴合进度末端
  • 用requestAnimationFrame保证动画平滑性

场景2:DOM+CSS方案

如果你的环形进度条是用DOM元素实现的,通过CSS变量和transform即可实现小圆跟随:

<div class="progress-wrap">
  <div class="bg-ring"></div>
  <div class="inner-ring" style="--progress: 0%"></div>
  <div class="follow-dot" style="--progress: 0%"></div>
</div>

<style>
.progress-wrap {
  position: relative;
  width: 200px;
  height: 200px;
}

/* 灰色背景环 */
.bg-ring {
  width: 100%;
  height: 100%;
  border: 10px solid #e0e0e0;
  border-radius: 50%;
  box-sizing: border-box;
}

/* 红色进度环 */
.inner-ring {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: 10px solid transparent;
  border-top-color: #ff3333;
  border-radius: 50%;
  box-sizing: border-box;
  /* 通过CSS变量控制旋转角度:1%对应3.6deg,减去90deg让起始点在顶部 */
  transform: rotate(calc(var(--progress) * 3.6deg - 90deg));
  transition: transform 0.2s linear;
}

/* 跟随小圆 */
.follow-dot {
  position: absolute;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #ff3333;
  top: 50%;
  left: 50%;
  /* 三步transform实现环形路径跟随:
     1. 居中定位
     2. 旋转到进度角度
     3. 平移到环形路径上
     4. 反向旋转保持小圆正立(可选)
  */
  transform: translate(-50%, -50%)
             rotate(calc(var(--progress) * 3.6deg - 90deg))
             translate(85px)
             rotate(calc(-(var(--progress) * 3.6deg - 90deg)));
  transition: transform 0.2s linear;
}
</style>

<script>
// 动画逻辑:逐步更新进度值
let progress = 0;
const innerRing = document.querySelector('.inner-ring');
const dot = document.querySelector('.follow-dot');

function updateProgress() {
  if (progress <= 100) {
    innerRing.style.setProperty('--progress', progress);
    dot.style.setProperty('--progress', progress);
    progress += 1;
    setTimeout(updateProgress, 30);
  }
}

updateProgress();
</script>

关键细节

  • 用CSS变量--progress统一控制进度环和小圆的动画参数
  • 平移距离85px是根据容器尺寸计算的:容器宽200px,边框10px,环形中线半径为(200-20)/2=90px,减去小圆半径7px得到85px
  • 最后一步反向旋转可以让小圆始终保持正立,不需要的话可以去掉

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 17:05:08