0

以下代码显示了一个橙色屏幕,右下角有一个绿色圆圈。可以拖动圆圈。

import SwiftUI

struct DraggableCircle: View {
    @Binding var offset: CGSize
    @State private var previousOffset: CGSize

    var body: some View {
        Circle().fill(Color.green)
            .frame(width: 100)
            .offset(self.offset)
            .gesture(
                DragGesture(minimumDistance: 0, coordinateSpace: .local)
                    .onChanged { event in
                        print("\nDragGesture onChanged")
                        self.offset = CGSize(width: event.location.x - (event.startLocation.x - self.previousOffset.width),
                                             height: event.location.y - (event.startLocation.y - self.previousOffset.height))
                    }
            )
    }

    init(offset: Binding<CGSize>) {
        print("Init with offset \(offset.wrappedValue)")
        self._offset = offset
        self._previousOffset = State(initialValue: offset.wrappedValue)
        print("offset = \(self.offset), previousOffset=\(self.previousOffset)")
    }
}

struct ContentView: View {
    @State var circleOffset = CGSize()

    var body: some View {
        GeometryReader { reader in
            Rectangle().fill(Color.orange)
                .overlay(
                    DraggableCircle(offset: self.$circleOffset)
                )
                .onAppear {
                    self.circleOffset = CGSize(width: reader.size.width / 2,
                                               height: reader.size.height / 2)
                    print("size: \(reader)\n")
                }
        }
    }
}

如果您运行并点击绿色圆圈(开始拖动手势),控制台中将显示以下内容:

Init with offset (0.0, 0.0)
offset = (0.0, 0.0), previousOffset=(0.0, 0.0)
size: GeometryProxy(base: SwiftUI._PositionAwareLayoutContext(base: SwiftUI.LayoutTraitsContext(context: AttributeGraph.AttributeContext<SwiftUI.VoidAttribute>(graph: __C.AGGraphRef(p: 0x00007f84b6a05ff0), attribute: AttributeGraph.Attribute<()>(identifier: __C.AGAttribute(id: 42))), environmentIndex: 4), dimensionsIndex: 1, transformIndex: 3, positionIndex: 2), seed: 1, viewGraph: Optional(SwiftUI.ViewGraph))

Init with offset (187.5, 323.5)
offset = (187.5, 323.5), previousOffset=(187.5, 323.5)

DragGesture onChanged
Init with offset (0.0, 0.0)
offset = (0.0, 0.0), previousOffset=(0.0, 0.0)

我期望发生的是,当你拖动圆圈时,它可以平滑地拖动到屏幕上的其他地方。

实际发生的情况是,当拖动开始时,DraggableCircle.init再次调用它会重置偏移量并将圆圈放在中间。为什么是这样?

注意:当您将@State previousOffset移入时ContentView,问题就会消失。但我不明白为什么。

4

1 回答 1

0

我根据您的评论更改了我的代码。在我的代码中,这个拖动手势可以正常工作。我现在看到的唯一错误是第一次激活拖动手势。也许这会引导您找到所需的解决方案。

        struct DraggableCircle: View {
    @Binding var circleOffset: CGSize
    @State private var previousOffset: CGSize

    var body: some View {
        Circle().fill(Color.green)
            .frame(width: 100)
            .offset(self.circleOffset)
            .gesture(
                DragGesture()
                    .onChanged { event in
                        print("\nDragGesture onChanged")
                            self.circleOffset = CGSize(width: event.location.x - (event.startLocation.x - self.previousOffset.width),
                                                       height: event.location.y - (event.startLocation.y - self.previousOffset.height))
                }
                .onEnded { event in
                    self.circleOffset = CGSize(width: event.location.x - (event.startLocation.x - self.previousOffset.width),
                                               height: event.location.y - (event.startLocation.y - self.previousOffset.height))

                    self.previousOffset = self.circleOffset
                }
        )
    }

    init(offset: Binding<CGSize>) {
        print("Init with offset \(offset.wrappedValue)")
        self._circleOffset = offset
        self._previousOffset = State(initialValue: offset.wrappedValue)
        print("offset = \(self.offset), previousOffset=\(self.previousOffset)")
    }
}

struct ContentView: View {
    @State var circleOffset = CGSize()

    var body: some View {
        GeometryReader { reader in
            Rectangle().fill(Color.orange)
                .overlay(
                    DraggableCircle(offset: self.$circleOffset)
                )
                .onAppear {
                    self.circleOffset = CGSize(width: reader.size.width / 2,
                                               height: reader.size.height / 2)
                    print("size: \(reader)\n")
                }
        }
    }
}
于 2020-05-31T20:15:26.437 回答