【问题标题】:SwiftUI DragGesture sets offset in infinite loop [duplicate]SwiftUI DragGesture 在无限循环中设置偏移量[重复]
【发布时间】:2021-10-14 01:03:42
【问题描述】:

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

它永远打印以下内容:

更改(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")
            }
    }
}

【问题讨论】:

    标签: swiftui


    【解决方案1】:

    您应该在gesture 之前应用offset

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

    变化:

    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)
            }
        }
    }
    
    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
            }
        }
    
        /* ... */
    }
    

    【讨论】:

      【解决方案2】:

      我需要指定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
         }
      

      【讨论】:

      • 谢谢,这对我来说效果很好。
      猜你喜欢
      • 2021-04-25
      • 1970-01-01
      • 1970-01-01
      • 2011-03-11
      • 1970-01-01
      • 2017-08-23
      • 1970-01-01
      • 2015-07-14
      • 1970-01-01
      相关资源
      最近更新 更多