在SwiftUI中复刻Apple Pay环形波纹效果
环形波纹效果实现方案
一、环形排列圆环
核心思路是围绕中心点,按固定角度间隔排布每个圆环,下面提供两种适合新手的实现方式:
方法1:CSS实现(上手简单)
- 搭建父容器作为定位基准,尺寸设为最大圆环的直径,开启相对定位。
- 每个圆环用绝对定位,先平移到父容器右侧边缘,再绕父容器中心旋转对应角度。
- 角度计算:若有N个圆环,每个圆环的旋转角度为
360°/N × 序号。
示例代码:
<div class="ripple-container"> <div class="ring"></div> <div class="ring"></div> <div class="ring"></div> <div class="ring"></div> <div class="ring"></div> <div class="ring"></div> <div class="ring"></div> <div class="ring"></div> <div class="center-icon">🔔</div> </div> <style> .ripple-container { position: relative; width: 200px; height: 200px; margin: 50px auto; } .ring { position: absolute; width: 100%; height: 100%; border-radius: 50%; transform-origin: center left; /* 旋转基点设为父容器中心左侧 */ } /* 给每个圆环分配旋转角度 */ .ring:nth-child(1) { transform: rotate(0deg); } .ring:nth-child(2) { transform: rotate(45deg); } .ring:nth-child(3) { transform: rotate(90deg); } .ring:nth-child(4) { transform: rotate(135deg); } .ring:nth-child(5) { transform: rotate(180deg); } .ring:nth-child(6) { transform: rotate(225deg); } .ring:nth-child(7) { transform: rotate(270deg); } .ring:nth-child(8) { transform: rotate(315deg); } .center-icon { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 40px; } </style>
方法2:Canvas实现(支持动态效果)
通过三角函数计算每个圆环的圆心坐标,实现环形排列:
- 确定画布中心坐标
(cx, cy),以及中心到圆环圆心的距离ringRadius。 - 每个圆环的圆心坐标公式:
x = cx + ringRadius × cos(弧度角度)y = cy + ringRadius × sin(弧度角度)
- 弧度角度计算:若有N个圆环,每个圆环的角度为
2π/N × 序号。
示例代码:
const canvas = document.getElementById('ripple-canvas'); const ctx = canvas.getContext('2d'); canvas.width = 300; canvas.height = 300; const cx = canvas.width / 2; const cy = canvas.height / 2; const ringCount = 8; // 圆环总数 const ringRadius = 60; // 中心到圆环圆心的距离 const singleRingSize = 40; // 单个圆环的半径 const ringWidth = 2; // 圆环线条宽度 // 批量绘制环形排列的圆环 for(let i = 0; i < ringCount; i++) { const angle = (Math.PI * 2 / ringCount) * i; const x = cx + ringRadius * Math.cos(angle); const y = cy + ringRadius * Math.sin(angle); ctx.beginPath(); ctx.arc(x, y, singleRingSize, 0, Math.PI * 2); ctx.lineWidth = ringWidth; ctx.strokeStyle = '#000'; ctx.stroke(); } // 绘制中间图标(用文字替代) ctx.font = '40px sans-serif'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText('🔔', cx, cy);
二、实现整体渐变效果
要让所有圆环呈现统一渐变,核心是让所有元素共享同一个渐变源,而非单独设置:
CSS方案:背景裁剪+路径裁剪
- 给父容器设置线性/径向渐变背景。
- 每个圆环用
clip-path剪出圆环形状,同时继承父容器的渐变背景。
修改CSS中.ring的样式:
.ring { /* 保留原有定位、旋转样式 */ background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); background-clip: text; -webkit-background-clip: text; /* 用两个圆形路径相减,得到圆环形状 */ clip-path: circle(50% at 50% 50%) circle(45% at 50% 50%); }
调整两个圆形的百分比,可以控制圆环的宽度。
Canvas方案:统一渐变笔触
创建一个全局渐变对象,所有圆环都使用这个渐变描边:
// 在绘制圆环前创建渐变 const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height); gradient.addColorStop(0, '#4facfe'); gradient.addColorStop(1, '#00f2fe'); // 绘制圆环时替换描边样式 ctx.strokeStyle = gradient;
额外优化:波纹扩散动画
给每个圆环添加延迟动画,模拟波纹扩散效果:
.ring { /* 保留原有样式 */ animation: ripple 2s infinite; --rotate: 0deg; transform: rotate(var(--rotate)); } /* 给每个圆环设置动画延迟 */ .ring:nth-child(1) { --rotate: 0deg; animation-delay: 0s; } .ring:nth-child(2) { --rotate: 45deg; animation-delay: 0.25s; } .ring:nth-child(3) { --rotate: 90deg; animation-delay: 0.5s; } .ring:nth-child(4) { --rotate: 135deg; animation-delay: 0.75s; } .ring:nth-child(5) { --rotate: 180deg; animation-delay: 1s; } .ring:nth-child(6) { --rotate: 225deg; animation-delay: 1.25s; } .ring:nth-child(7) { --rotate: 270deg; animation-delay: 1.5s; } .ring:nth-child(8) { --rotate: 315deg; animation-delay: 1.75s; } @keyframes ripple { 0% { transform: rotate(var(--rotate)) scale(1); opacity: 1; } 100% { transform: rotate(var(--rotate)) scale(1.5); opacity: 0; } }
内容的提问来源于stack exchange,提问作者Codelaby
相关产品推荐
相关产品推荐

