Swift PlaygroundsでTapGesture、longPressGestureを学ぶ

SwiftUI

概要:

TapGesture、longPressGestureを学びます。

iPadのアプリSwift Playgroundsの中の「ジェスチャの認識」のソースコードで説明します。

「ジェスチャの認識」のファイルとViewの構成

早速ですが、今回も構成図を作ってみました。

構成はシンプルですね。

ContentViewのListから選ばれた項目のViewがNavigationLinkで呼び出されているだけです。

GestureRowはListの各項目の中の表示を担当しています。

今回はTapViewで使っているTapGesture、LongPressViewで使われているLongPressGestureを分かり易く解説していきます。

TapGesture、onTapGesture

まず、TapViewのファイルを見てみましょう。リストからTapを選択された時の画面を扱うViewです。四角内をクリックすると四角の色が変わります。

TapViewファイルのメインのコードの部分を見てみます。

struct TapView: View {
    @State private var color : Color = Color.primary

    var tapGesture: some Gesture {
        TapGesture()
            .onEnded {
                withAnimation {
                    color = Color.random()
                }
            }
    }
 
    var body: some View {
        VStack {
            Text("Tap the rectangle to change its color")
            Spacer()
            Rectangle()
                .foregroundColor(color)
                .frame(width: 250, height: 450)
                .gesture(tapGesture)
             Spacer()
        }
        .navigationTitle("Tap")
        .padding()
        .toolbar {
            Button("Reset") {
                color = Color.primary
            }
        }
    }
}

var tapGesture: some Gesture { } では、Gestureプロトコルに準拠した独自のtapGestureを定義しています。タップされた時に独自の処理にあたります。

タップの基本的な動作をつかさどるTapGestureという構造体のインスタンスを作成し、そのメソッドであるonEnded(タップ操作が終了した時に呼ばれる)の{ }内に独自の処理を書いています。

ここでの処理というのは、
タップされた時(正確にはタップ操作が終わった時)に「アニメーション付きでRectangleの色をランダムな色に変える」
という記述になります。

その定義をRectangleの.gestureというモディファイヤーに渡しています。

同じ処理を、別な書き方も可能です。

struct TapView: View {
    @State private var color : Color = Color.primary
 
    var body: some View {
        VStack {
            Text("Tap the rectangle to change its color")
            Spacer()
            Rectangle()
                .foregroundColor(color)
                .frame(width: 250, height: 450)
                // .gesture(tapGesture)
                .onTapGesture {  // ← ここ 
                    withAnimation {
                        color = Color.random()
                    }
                }
             Spacer()
        }
        .navigationTitle("Tap")
        .padding()
        .toolbar {
            Button("Reset") {
                color = Color.primary
            }
        }
    }
}

var tapGesture: some Gesture { } の部分は削除し、Rectangleに直接onTapGestureというモディファイヤーで処理を書いています。

プログラムの中で1箇所だけでしたらこのような書き方もあります。onTapGestureにはonEndedの意味も含まれています。

複数箇所に同じtapGestureを使うなら定義する方がわかりやすいのではないでしょうか。
このサンプルプログラムでは他のGestureも全て定義する方法で記述されています。

ちなみに今回の記述ではダブルクリックには対応しておりません。
2回色が変わります(笑)

通常クリックに加え、ダブルクリックにも対応するためには
TapGesture(count: 2)とか、.onTapGesture(count: 2)という記述も併記します。

その際、count: 2の方を先に記述しないとうまく動作しませんので注意です。

以下にダブルクリックも対応したプログラムを参考に載せておきます。

ダブルクリック時には色を初期値に戻すようにしたしています。

            Rectangle()
                .foregroundColor(color)
                .frame(width: 250, height: 450)
                .onTapGesture(count: 2) {
                    withAnimation {
                        color = Color.primary
                    }
                }
                .onTapGesture {
                    withAnimation {
                        color = Color.random()
                    }
                }

いかがでしょうか。

TapGestureはジェスチャ系の基本でもあります。

これを踏まえて次に進みます。

LongPressGesture

アプリ「ジェスチャの認識」で「Touch and Hold」を選択した時の処理です。特に長押しの処理を見ていきます。

以下がLongPressViewのソースコードです。
TapViewと基本構成は同じですね。

struct LongPressView: View {
    @State private var sizeIndex = 0
    
    private var sizes: [CGSize] = [
        CGSize(width: 150, height: 80),
        CGSize(width: 200, height: 40),
        CGSize(width: 50, height: 250),
        CGSize(width: 220, height: 100),
        CGSize(width: 90, height: 90),
    ]

    var longPressGesture: some Gesture {
        LongPressGesture()
            .onEnded { value in
                withAnimation {
                    sizeIndex += 1
                    if sizeIndex == sizes.count {
                        sizeIndex = 0
                    }
                }
            }
    }
    
    var body: some View {
        VStack {
            Text("Touch and hold the capsule to change its size")
            Spacer()
            Capsule()
                .foregroundColor(.yellow)
                .frame(width: sizes[sizeIndex].width, height: sizes[sizeIndex].height)
                .gesture(longPressGesture)
            Spacer()
        }
        .navigationTitle("Touch and Hold")
        .padding()
        .toolbar {
            Button("Reset") {
                sizeIndex = 0
            }
        }
    }
}

カプセルを長押しする度に、カプセルの縦と横の長さが変わるという単純動作です。縦横の長さはsizesという配列で定義された5組がループで代入されます。

TapGestureの時と違って、.onEnded {の後ろにvalue inがついていますね。
LongPressGestureの時はこれを省略できません。

.onEnded { value in
    // 長押しが成立した時の処理(valueの値を使うことが可能)
}

valueはonEndedが呼ばれた時にtrueになってるフラグですが、ほとんど使い道はないかと。。
このサンプルプログラムでも使っていませんので、次のように省略して書いても良いです。

.onEnded { _ in
    // 長押しが成立した時の処理
}

LongPressGestureでは、押している間隔を設定することができます。

        LongPressGesture(minimumDuration: 3.0)

値は秒です。上の表記は3秒間押されたら長押しと認識する、という意味になります。


最後に:

今回はiPadのアプリSwift Playgroundsの「ジェスチャの認識」のソースコードを使ってTapGestureとLongPressGestureを学びました。

最後まで読んで頂いて、ありがとうございます。

次回は同じソースコードを使ってDragGestureを徹底的に解説してみようと思います

ご意見、ご指摘等ありましたら、コメントを頂けると大変嬉しいです。

コメント

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