在DragGesture onChanged之后视图会重新初始化

时间:2020-05-31 17:54:56

标签: swiftui draggesture

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

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时,问题消失了。但是我不明白为什么。

1 个答案:

答案 0 :(得分: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")
                }
        }
    }
}