SwiftUI DragGesture 在无限循环中设置偏移量

Rob*_*b N 4 swiftui

我想将一个视图拖动到ZStack. 在此示例代码中,Toolbar有一个蓝色的可拖动区域。通过设置 .它应该Toolbar在屏幕上移动offset。相反,它会进入无限循环。如何固定才能正确拖动?

它永远打印以下内容:

改变 (36.5, 27.0)
改变 (0.0, 0.0)

extension CGPoint {
    func toSize() -> CGSize { .init(width:x, height:y) }
}

struct ContentView: View {
    @State var offset: CGSize = .zero
    var body: some View {
        ZStack(alignment: .topLeading) {
            Toolbar(dragOffset: $offset)
                .offset(offset)
            Text(verbatim: "Offset: \(offset)")
                .frame(maxWidth: .infinity, maxHeight: .infinity)
        }
    }
}

struct Toolbar: View {
    @Binding var dragOffset: CGSize
    var body: some View {
        HStack {
            Color.blue.frame(width: 40, height: 40)
                .gesture(drag)
            Color.green.frame(width: 40, height: 40)
            Color.red.frame(width: 40, height: 40)
        }
    }
    var drag: some Gesture {
        DragGesture()
            .onChanged { value in
                print("changed \(value.location)")
                dragOffset = value.location.toSize()
            }
            .onEnded { value in
                print("ended")
            }
    }
}

Run Code Online (Sandbox Code Playgroud)

Rob*_*b N 7

我需要指定 a CoordinateSpace,因为默认值是.local. 使用.global作品。命名空间也应该有效。

@State将初始偏移记录在变量中,然后使用该起始值加上拖动的 来设置新值也很有帮助translation

@State private var dragStartOffset: CGSize? = nil
...
DragGesture(coordinateSpace: .global)
   .onChanged { value in
       if dragStartOffset == nil {
           dragStartOffset = dragOffset
       }
       dragOffset = dragStartOffset! + value.translation
   }
   .onEnded { _ in 
       dragStartOffset = nil
   }
Run Code Online (Sandbox Code Playgroud)


Geo*_*e_E 6

您应该在offset之前应用gesture

这可以确保您不会在屏幕上拖动时创建无限循环,偏移会发生变化,然后再次更改视图的位置。这意味着您的手势偏移现已更改,从而创建了无限循环。

变化:

struct ContentView: View {
    @State var offset: CGSize = .zero
    var body: some View {
        ZStack(alignment: .topLeading) {
            Toolbar(dragOffset: $offset)
//                .offset(offset) // <- REMOVE THIS
            Text(verbatim: "Offset: \(offset)")
                .frame(maxWidth: .infinity, maxHeight: .infinity)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
struct Toolbar: View {
    @Binding var dragOffset: CGSize
    var body: some View {
        HStack {
            Color.blue.frame(width: 40, height: 40)
                .offset(dragOffset) // <- ADD THIS
                .gesture(drag)

            Color.green.frame(width: 40, height: 40)
                .offset(dragOffset) // <- ADD THIS

            Color.red.frame(width: 40, height: 40)
                .offset(dragOffset) // <- ADD THIS
        }
    }

    /* ... */
}
Run Code Online (Sandbox Code Playgroud)