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

SwiftUI实现渐变大小同心点状圆环及屏幕适配问题

实现带渐变圆点的同心圆环SwiftUI视图

现有代码及问题

当前用于绘制同心圆环的SwiftUI视图代码如下:

struct TestView: View {
    var body: some View {
            ZStack {
                Color.red
                ForEach((0...50), id: \.self) { index in
                    
                    Path { path in
                        var radius = CGFloat(120 + (index * 30))
                        let center = (x: UIScreen.main.bounds.size.width/2, y: UIScreen.main.bounds.size.height/2)
                        path.move(to: CGPoint(x: center.x + radius, y: center.y))
                        path.addArc(center: CGPoint(x: center.x, y: center.y), radius: radius, startAngle: Angle(degrees: 0), endAngle: Angle(degrees: 360), clockwise: false)
                    }
                    .stroke(Color.white, style: StrokeStyle(lineWidth: 1, lineCap: .round, lineJoin: .round, dash: [3.0]))
                }
            }
    }
}

现有问题:

  • 虚线样式不符合需求,需替换为圆形圆点
  • 圆点大小和间距固定,无法随圆环向外扩展递增
  • 使用UIScreen.main.bounds导致适配安全区域时上下圆弧显示不均,且无法让圆环自然超出屏幕边界

需求目标

  • 将虚线替换为圆形圆点,圆点大小与间距随圆环半径增大而逐渐变大
  • 圆环超出屏幕边界但保持居中显示,适配安全区域

修改后的实现代码

struct TestView: View {
    // 可配置参数,方便调整视觉效果
    private let ringCount = 50
    private let initialRadius: CGFloat = 20
    private let radiusStep: CGFloat = 25
    private let initialDotSize: CGFloat = 2
    private let dotSizeStep: CGFloat = 0.3
    private let initialDotSpacing: CGFloat = 8
    private let dotSpacingStep: CGFloat = 0.8
    
    var body: some View {
        ZStack {
            Color.red
                .ignoresSafeArea() // 让背景及圆环延伸至安全区域外
            
            // 通过GeometryReader获取容器尺寸,替代UIScreen.main.bounds实现精准居中
            GeometryReader { proxy in
                let center = CGPoint(x: proxy.size.width / 2, y: proxy.size.height / 2)
                
                ForEach(0..<ringCount, id: \.self) { index in
                    let radius = initialRadius + CGFloat(index) * radiusStep
                    let dotSize = initialDotSize + CGFloat(index) * dotSizeStep
                    // 利用round线帽特性,将0长度虚线段渲染为圆点,间距随索引递增
                    let dashSpacing = initialDotSpacing + CGFloat(index) * dotSpacingStep
                    
                    Path { path in
                        path.move(to: CGPoint(x: center.x + radius, y: center.y))
                        path.addArc(center: center, radius: radius, startAngle: .zero, endAngle: .degrees(360), clockwise: false)
                    }
                    .stroke(Color.white, style: StrokeStyle(
                        lineWidth: dotSize,
                        lineCap: .round,
                        lineJoin: .round,
                        dash: [0, dashSpacing]
                    ))
                }
            }
        }
    }
}

关键修改说明

  • 适配安全区域与屏幕边界:
    • 使用GeometryReader获取当前容器的实际尺寸,替代UIScreen.main.bounds,确保在任何布局环境下都能计算出精准的中心位置
    • 背景色添加.ignoresSafeArea(),允许圆环自然延伸到安全区域外,同时保持整体居中对齐
  • 动态圆点效果:
    • 通过index动态计算每个圆环的lineWidth(即圆点大小)和dash数组的间距值,实现向外扩展时圆点逐渐变大、间距逐渐变宽的效果
    • 利用lineCap: .round特性,将长度为0的虚线段渲染为圆形圆点,避免手动绘制单个圆点带来的性能损耗
  • 参数可配置:将初始半径、步长、圆点初始大小等参数抽为私有常量,方便快速调整整体视觉风格

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 03:52:48