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

如何在SwiftUI中优雅实现圆周12等分段的绘制?

更优雅的SwiftUI实现12段等分圆周方案

针对你当前用12个重复Circle视图实现分段圆周的方式,这里提供三种更简洁、可维护性更强的实现方案:

方案一:用ForEach简化重复代码

将重复的Circle视图通过循环生成,把关键参数抽为常量,方便后续修改:

struct SegmentedCircleView: View {
    private let segmentCount = 12
    private let lineWidth: CGFloat = 25
    private let gapRatio: CGFloat = 0.001 // 段间间隙占单段的比例
    private let segmentRatio = 1.0 / 12
    
    var body: some View {
        ZStack {
            ForEach(0..<segmentCount, id: \.self) { index in
                Circle()
                    .trim(
                        from: (CGFloat(index) * segmentRatio) + gapRatio,
                        to: (CGFloat(index + 1) * segmentRatio) - gapRatio
                    )
                    .stroke(Color.black, lineWidth: lineWidth)
            }
        }
        .padding(30)
    }
}

优势:代码量大幅减少,参数集中管理,修改段数、间隙、线宽只需调整常量,可读性强。

方案二:自定义Shape绘制(性能最优)

通过自定义Shape直接绘制所有分段圆弧,仅需一个视图实例,性能更出色:

struct SegmentedCircle: Shape {
    let segmentCount: Int = 12
    let gapRatio: CGFloat = 0.001
    let lineWidth: CGFloat = 25
    
    func path(in rect: CGRect) -> Path {
        var path = Path()
        let radius = min(rect.width, rect.height) / 2 - lineWidth / 2
        let center = CGPoint(x: rect.midX, y: rect.midY)
        let totalAngle = 2 * CGFloat.pi
        let segmentAngle = totalAngle / CGFloat(segmentCount)
        let gapAngle = gapRatio * totalAngle
        
        for index in 0..<segmentCount {
            let startAngle = CGFloat(index) * segmentAngle + gapAngle / 2
            let endAngle = startAngle + segmentAngle - gapAngle
            
            path.addArc(
                center: center,
                radius: radius,
                startAngle: startAngle,
                endAngle: endAngle,
                clockwise: false
            )
        }
        
        return path.strokedPath(.init(lineWidth: lineWidth, lineCap: .butt))
    }
}

// 使用示例
struct SegmentedCircleView: View {
    var body: some View {
        SegmentedCircle()
            .foregroundColor(.black)
            .padding(30)
    }
}

优势:仅需一个视图,避免多视图叠加的性能开销,可灵活控制圆弧的绘制细节,比如线帽、间隙的精准度。

方案三:利用StrokeStyle的dashPattern(最简洁)

借助SwiftUI的StrokeStyle的dash参数,直接实现分段效果,代码最精简:

struct SegmentedCircleView: View {
    private let segmentCount = 12
    private let lineWidth: CGFloat = 25
    private let gapLength: CGFloat = 2 // 段间间隙的实际长度,可按需调整
    
    var body: some View {
        GeometryReader { proxy in
            let diameter = min(proxy.size.width, proxy.size.height) - 30 * 2 - lineWidth
            let circumference = CGFloat.pi * diameter
            let segmentLength = (circumference / CGFloat(segmentCount)) - gapLength
            
            Circle()
                .stroke(
                    Color.black,
                    style: StrokeStyle(
                        lineWidth: lineWidth,
                        lineCap: .butt,
                        dash: [segmentLength, gapLength]
                    )
                )
        }
        .padding(30)
    }
}

优势:代码极简,仅需一个Circle视图,利用系统原生的虚线实现逻辑,无需手动处理多个圆弧段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 08:53:31