【SwiftUI】onLongPressGestureを離した時に実行する

SwiftUI

SwiftUI長押しを実装する際にonLongPressGestureやLongPressGestureを使用します。
これは通常、指定した時間長押しすると手を離さずとも実行されます。

今回はこれを手を離したタイミングで実行する方法を紹介します。

実装方法

LongPressGestureの前にgestureを追加してDragGestureを実装します。
DragGestureの中身は不要です。

こうする事でDragGestureが優先される為、DragGestureの判定が終わるまでLongPressGestureが実行されません。
DragGestureは指を離したタイミングで終わるので、LongPressGestureの実行も指を離すまで実行されません。

なお、DragGestureを後に実装するとLongPressGestureは通常通り動作します。
この場合はLongPressGestureが実行されるとDragGestureが実行されません。
SwiftUIではよくある事ですがModifierの順序には気をつけましょう。

サンプルコード

Textのgestureをつけたものを2つ用意しました。
もちろんonLongPressGestureはgesture(LongPressGesture())でも問題ありません。

動作の違いを確認してみてください。

struct SampleView: View {
    var body: some View {
        VStack {
            Text("Pressing")
                .padding()
                .onLongPressGesture{
                    print("LongPress")
                }
                //LongPressGestureはどちらでも良い
//                .gesture(LongPressGesture().onEnded{ _ in
//                    print("LongPress")
//                })
                .gesture(DragGesture().onEnded{ _ in
                    print("Drag")
                })
            
            Text("Release")
                .padding()
                .gesture(DragGesture().onEnded{ _ in
                    print("Drag")
                })
                .onLongPressGesture{
                    print("LongPress")
                }
        }

    }
}

動画で違いを確認する

gestureの順序の違いがわかる動画を用意しました。
見やすいように色々追加していますが、やっている事は先程のコードと同様です。

おまけ

動画で使ったViewのコードです。

struct MovieView: View {
    
    @State var text = "None"
    
    var body: some View {
        NavigationStack {
            VStack {
                Spacer()
                Text("LongPressGestureの\n実行タイミングを変える")
                    .multilineTextAlignment(.center)
                    .font(.title2)
                
                Spacer()
                
                VStack {
                    Text("Pressing")
                        .font(.title)
                        .foregroundColor(.white)
                        .frame(width: 150)
                        .padding()
                        .background(.blue)
                        .cornerRadius(10)
                        .gesture(LongPressGesture().onEnded{ _ in
                            text = "LongPress"
                            setNone()
                        })
                        .gesture(DragGesture().onEnded{ _ in
                            text = "Drag"
                            setNone()
                        })
                    .padding()
                    
                    Text("Release")
                        .font(.title)
                        .foregroundColor(.white)
                        .frame(width: 150)
                        .padding()
                        .background(.blue)
                        .cornerRadius(10)
                        .gesture(DragGesture().onEnded{ _ in
                            text = "Drag"
                            setNone()
                        })
                        .gesture(LongPressGesture().onEnded{ _ in
                            text = "LongPress"
                            setNone()
                        })
                        .padding()
                }
                
                Spacer()
                
                VStack {
                    HStack {
                        Text("Status")
                            .font(.title3)
                        Spacer()
                    }
                    Text(text)
                        .font(.title)
                }.frame(width: 150)
                
                Spacer()
            }.navigationTitle("LongPressGesture")
        }
    }
    
    func setNone(){
        Task{
            try? await Task.sleep(nanoseconds: 2 * 1000 * 1000 * 1000)
            await MainActor.run{
                text = "None"
            }
        }
    }
}

コメント

タイトルとURLをコピーしました