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

SwiftUI Canvas中利用DragGesture实现直线绘制的问题及需求

解决SwiftUI Canvas绘制直线的轨迹混乱问题

问题说明

尝试使用SwiftUI的Canvas和DragGesture绘制直线,但当前代码只能得到无固定轨迹的混乱线条,需要实现拖拽时实时显示从起点到当前位置的直线,拖拽结束后固定该直线的效果。

当前效果

现有效果动图

期望效果

期望效果动图

当前代码问题分析

原代码在DragGesture的onChanged中不断将当前位置追加到lines数组,然后遍历数组绘制所有点的连线,导致轨迹是连续拖拽路径的折线,而非从固定起点到当前位置的直线,同时缺少拖拽开始/结束的状态管理,无法固定已绘制的直线。

修改后的代码

import SwiftUI

struct GraphicDictView: View {
    // 存储已完成的直线(每条直线包含起点和终点)
    @State private var completedLines: [(start: CGPoint, end: CGPoint)] = []
    // 存储正在绘制的临时直线(起点+当前拖拽位置)
    @State private var currentLine: (start: CGPoint, end: CGPoint)?
    // 跟随拖拽的圆点位置
    @State private var circlePosition = CGPoint()
    
    var body: some View {
        Canvas { context, _ in
            // 绘制已完成的所有直线
            for line in completedLines {
                let path = Path { p in
                    p.move(to: line.start)
                    p.addLine(to: line.end)
                }
                context.stroke(path, with: .color(.blue), lineWidth: 2)
            }
            
            // 绘制正在拖拽的临时直线
            if let currentLine = currentLine {
                let path = Path { p in
                    p.move(to: currentLine.start)
                    p.addLine(to: currentLine.end)
                }
                context.stroke(path, with: .color(.blue), lineWidth: 2)
            }
            
            // 绘制跟随的蓝色圆点
            context.fill(
                Path(ellipseIn: CGRect(
                    x: circlePosition.x - 7,
                    y: circlePosition.y - 7,
                    width: 14,
                    height: 14
                )),
                with: .color(.blue)
            )
        }
        .gesture(
            DragGesture()
                .onStarted { value in
                    // 拖拽开始时记录起点,初始化临时直线
                    currentLine = (start: value.location, end: value.location)
                    circlePosition = value.location
                }
                .onChanged { value in
                    // 拖拽过程中更新临时直线的终点和圆点位置
                    currentLine?.end = value.location
                    circlePosition = value.location
                }
                .onEnded { value in
                    // 拖拽结束时,将临时直线加入已完成数组,清空临时直线
                    if let line = currentLine {
                        completedLines.append(line)
                    }
                    currentLine = nil
                }
        )
    }
}

关键改动说明

  • 状态拆分:用completedLines存储已固定的直线,currentLine存储正在绘制的临时直线,避免轨迹混乱
  • 手势全生命周期处理:
    • onStarted:记录拖拽起点,初始化临时直线
    • onChanged:实时更新临时直线的终点,同步圆点位置
    • onEnded:将临时直线保存到已完成数组,清空临时状态
  • Canvas绘制逻辑:先绘制已完成的直线,再绘制临时直线,确保层级正确

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 21:43:12