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

SwiftUI轨迹绘制异常求助:拖拽圆形轨迹呈矩形而非平滑曲线

问题分析与修复方案

你的轨迹呈现矩形而非平滑曲线,核心是三个关键逻辑错误:

1. Path绘制逻辑断裂

循环里每次调用addLine(to:)后又执行move(to:),会让每个点都成为新路径的起点,所有线段都孤立存在,根本无法连成连续曲线。应该只在循环前设置初始起点,循环内仅调用addLine(to:)来连接点。

2. 轨迹纵向坐标计算不稳定

你用(geo.size.height / 2) / CGFloat(track.count)计算Y坐标,当track.count达到100并开始移除元素时,数组长度会在99和100之间波动,导致高度值跳变,轨迹出现上下抖动。需要固定轨迹区域的总高度,按固定步长分配每个点的Y坐标。

3. Timer触发过于频繁

Timer.publish(every: 0.001)相当于每秒触发1000次,不仅浪费性能,还会让轨迹点过于密集,反而影响流畅度。建议调整为0.02~0.05秒的间隔,平衡流畅度和性能。


修复后的完整代码

import SwiftUI

struct ContentView: View {
    @State private var track = [CGFloat]()
    @State private var offset: CGFloat = 0
    // 调整Timer间隔为0.02秒(每秒50次)
    let timer = Timer.publish(every: 0.02, on: .current, in: .common).autoconnect()
    // 固定轨迹点数量,避免长度波动
    private let maxTrackPoints = 100

    var body: some View {
        GeometryReader { geo in
            ZStack {
                Color.black
                Path { path in
                    guard !track.isEmpty else { return }
                    
                    // 固定轨迹区域的总高度为屏幕下半部分
                    let totalTrackHeight = geo.size.height / 2
                    // 每个点的纵向步长固定
                    let yStep = totalTrackHeight / CGFloat(maxTrackPoints - 1)
                    
                    // 设置路径起点
                    let startX = geo.size.width * track[0]
                    path.move(to: CGPoint(x: startX, y: 0))
                    
                    // 循环连接所有轨迹点
                    for i in 1..<track.count {
                        let x = geo.size.width * track[i]
                        let y = yStep * CGFloat(i)
                        path.addLine(to: CGPoint(x: x, y: y))
                    }
                }
                .stroke(lineWidth: 1)
                .foregroundStyle(.yellow)
                // 让轨迹显示在屏幕下半部分
                .position(x: geo.size.width / 2, y: geo.size.height * 3/4)
                
                Circle()
                    .frame(width: 25)
                    .foregroundStyle(.red)
                    .position(x: offset, y: geo.size.height / 2)
                    .gesture(
                        DragGesture()
                            .onChanged { value in
                                offset = min(geo.size.width - 15, max(15, value.location.x))
                            }
                    )
                    .onAppear {
                        offset = geo.size.width / 2
                    }
                    .onReceive(timer) { _ in
                        track.append(offset / geo.size.width)
                        if track.count >= maxTrackPoints {
                            track.removeFirst()
                        }
                    }
            }
        }
    }
}

额外优化建议

  • 如果想要更平滑的曲线,可以把addLine(to:)换成addQuadCurve(to:control:)或addCurve(to:control1:control2:),用贝塞尔曲线连接点
  • 可以给轨迹添加渐隐效果,让最早的轨迹点透明度更低,增强视觉层次感

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 12:22:19