🦋

SwiftUI: DragGestureは2本指ドラッグするとonEnded()が不発

2023/08/26に公開

DragGestureを適用したViewにまず1本指で触れてドラッグした後、触れる指をもう一本追加するとonEnded()が不発のままDragGestureがキャンセルされます。

struct TouchView: View {
    let onTouchDownHandler: () -> Void
    let onTouchUpHandler: () -> Void

    var body: some View {
        Rectangle()
            .frame(width: 100, height: 40)
            .gesture(
                DragGesture(minimumDistance: 0.0, coordinateSpace: .local)
                    .onChanged { _ in
                        onTouchDownHandler()
                    }
                    .onEnded { _ in
                        onTouchUpHandler()
                    }
            )
    }
}

なので、上記のようなViewではonTouchUpHandler()が呼ばれず、意図しない挙動をする可能性があります。そこで、onEnded()ではなくupdating()を使うことで、キャンセルの場合も処理をハンドリングできます。

struct TouchView: View {
    @GestureState var isGestureActive: Bool = false
    let onTouchDownHandler: () -> Void
    let onTouchUpHandler: () -> Void

    var body: some View {
        Rectangle()
            .frame(width: 100, height: 40)
            .gesture(
                DragGesture(minimumDistance: 0.0, coordinateSpace: .local)
                    .onChanged { _ in
                        onTouchDownHandler()
                    }
                    .updating($isGestureActive) { _, state, _ in
                        state = true
                    }
            )
            .onChange(of: isGestureActive) { newValue in
                if !newValue {
                    onTouchUpHandler()
                }
            }
    }
}

参考
SwiftUI で Gesture キャンセルを検出する

Discussion