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

SwiftUI如何使用onDrag手势实现多元素独立拖拽?

解决方案

问题原因

所有矩形共用同一个全局offset状态变量,任意拖拽操作修改该变量时,所有绑定该变量的视图都会同步偏移,因此出现全部矩形一起移动的问题。同时原代码的手势逻辑存在缺陷,下次拖拽时矩形会跳回初始位置。

实现思路

将可拖拽的矩形封装为独立子视图,每个子视图单独持有自己的偏移状态,各个实例的状态互不干扰,即可实现单个矩形独立拖拽的效果。同时优化手势存储逻辑,避免拖拽跳转问题。

修正后完整代码

import SwiftUI

// 封装独立的可拖拽矩形子视图
struct DraggableRectangle: View {
    // 每个矩形自己持有的偏移状态,和其他实例互不影响
    @State private var offset: CGSize = .zero
    // 存储上次拖拽结束的位置,避免下次拖拽跳回原点
    @State private var lastOffset: CGSize = .zero
    
    var body: some View {
        Rectangle()
            .fill(.green)
            .frame(width: 50, height: 50)
            .cornerRadius(10)
            .shadow(color: .black, radius: 10, x: 10, y: 10)
            .overlay(
                Text("O")
                    .font(.largeTitle)
                    .foregroundColor(.white)
            )
            .offset(offset)
            .gesture(
                DragGesture()
                    .onChanged { value in
                        withAnimation(.spring()) {
                            // 本次偏移 = 上次结束的偏移 + 当前拖拽的位移
                            offset = CGSize(
                                width: lastOffset.width + value.translation.width,
                                height: lastOffset.height + value.translation.height
                            )
                        }
                    }
                    .onEnded { value in
                        withAnimation(.spring()) {
                            // 拖拽结束后存储当前位置为下次拖拽的初始值
                            lastOffset = offset
                        }
                    }
            )
    }
}

struct GameView: View {
    var body: some View {
        ZStack{
            Image("Wolffront")
            
            VStack(spacing: 10){
                // 直接调用子视图即可,每个实例独立管理自己的拖拽状态
                DraggableRectangle()
                DraggableRectangle()
                // 后续需要更多矩形只需要新增一行即可
                // DraggableRectangle()
            }
        }
        // navigationBarHidden放到父视图层级即可,不需要重复写在每个子视图上
        .navigationBarHidden(true)
    }
}
    
struct GameView_Previews: PreviewProvider {
    static var previews: some View {
        GameView()
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 02:48:00