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

如何消除Xcode 17中拖拽选择网格单元格的延迟问题?

10×10网格拖拽选择启动延迟问题解决

问题描述

在Mac端Xcode 17中用SwiftUI实现10×10网格的单元格选择功能,功能可运行但拖拽选择启动时存在延迟,常漏选前一两个单元格,后续选择正常。期望点击单元格并拖拽时立即将单元格标蓝直至停止拖拽,但实际总有短暂延迟;仅缓慢拖拽时才可能正常选中起始单元格。

附原代码:

import SwiftUI

let cellSize: CGFloat = 30

struct ContentView: View {
    @State var cellColors: [[Color]] = Array(repeating: Array(repeating: .white, count: 10), count: 10)
    
    var body: some View {
        VStack {
            ZStack() {
                Rectangle()             //Bounding box for grid
                    .fill(Color.clear)
                    .stroke(Color.red, lineWidth: 0)
                    .frame(width: 10 * cellSize, height: 10 * cellSize)
                    .coordinateSpace(name: "Grid")
                
                VStack(spacing: 0){
                    ForEach (0..<10, id: \.self){row in
                        GridRow(content: {
                            HStack(spacing: 0){
                                ForEach (0..<10, id: \.self){column in
                                    Rectangle()
                                        .fill(cellColors[row][column])
                                        .stroke(Color.yellow, lineWidth: 2)
                                        .frame(width: cellSize, height: cellSize)
                                        .onTapGesture {coord in
                                            cellColors[row][column] = .red
                                            print("Tap: \(row), \(column)")
                                        }
                                }
                            }
                        })
                    }
                }
                .padding()
                .frame(width: 10 * cellSize, height: 10 * cellSize)
                .gesture(DragGesture(minimumDistance: 0,
                                     coordinateSpace: .named("Grid"))
                    .onChanged() { drag in
                        let cellRow = Int(drag.location.y/cellSize)
                        let cellColumn = Int(drag.location.x/cellSize)
                        cellColors[cellRow][cellColumn] = .blue
                    }
                    .onEnded() { drag in
                        print("DragEnd: \(drag.location)")
                    }
                )
            }
        }
    }
}

注:提问者为资深Lisp开发者,正重新学习SwiftUI开发,已尽量精简代码。

问题原因

延迟源于DragGesture的onChanged回调不会触发初始点击位置——即便minimumDistance设为0,首次onChanged也需要微小位移才会执行,导致快速拖拽时起始单元格被跳过。

解决方法

结合DragGesture的updating方法处理初始拖拽位置,利用GestureState跟踪拖拽状态,确保起始单元格在拖拽启动时立即被选中。

修改后的代码:

import SwiftUI

let cellSize: CGFloat = 30

struct ContentView: View {
    @State var cellColors: [[Color]] = Array(repeating: Array(repeating: .white, count: 10), count: 10)
    @GestureState private var isDragging = false
    
    var body: some View {
        VStack {
            ZStack() {
                Rectangle()
                    .fill(Color.clear)
                    .frame(width: 10 * cellSize, height: 10 * cellSize)
                    .coordinateSpace(name: "Grid")
                
                VStack(spacing: 0){
                    ForEach (0..<10, id: \.self){row in
                        GridRow {
                            HStack(spacing: 0){
                                ForEach (0..<10, id: \.self){column in
                                    Rectangle()
                                        .fill(cellColors[row][column])
                                        .stroke(Color.yellow, lineWidth: 2)
                                        .frame(width: cellSize, height: cellSize)
                                        .onTapGesture {
                                            cellColors[row][column] = .red
                                            print("Tap: \(row), \(column)")
                                        }
                                }
                            }
                        }
                    }
                }
                .padding()
                .frame(width: 10 * cellSize, height: 10 * cellSize)
                .gesture(
                    DragGesture(minimumDistance: 0, coordinateSpace: .named("Grid"))
                        .updating($isDragging) { value, state, transaction in
                            state = true
                            // 处理初始拖拽位置
                            let cellRow = Int(value.startLocation.y / cellSize)
                            let cellColumn = Int(value.startLocation.x / cellSize)
                            guard cellRow >= 0, cellRow < 10, cellColumn >= 0, cellColumn < 10 else { return }
                            cellColors[cellRow][cellColumn] = .blue
                        }
                        .onChanged { drag in
                            let cellRow = Int(drag.location.y / cellSize)
                            let cellColumn = Int(drag.location.x / cellSize)
                            guard cellRow >= 0, cellRow < 10, cellColumn >= 0, cellColumn < 10 else { return }
                            cellColors[cellRow][cellColumn] = .blue
                        }
                        .onEnded { drag in
                            print("DragEnd: \(drag.location)")
                        }
                )
            }
        }
    }
}

关键改进点

  • 新增@GestureState跟踪拖拽状态,确保updating方法在拖拽启动时立即执行。
  • 在updating中处理startLocation(初始点击位置),保证起始单元格被立即选中。
  • 添加边界范围检查,避免数组越界访问。

修改后拖拽启动延迟消失,起始单元格会立即标蓝,快速拖拽也不会漏选。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 00:18:10