【SwiftUI】タップ/長押しイベントを取得する方法!Gestureメソッドの使い方

この記事からわかること

  • Swift UIタップイベント取得する方法
  • onTapGesture/onLongPressGestureの使用方法
  • Gesture(ジェスチャー)とは?
  • ジェスチャー構造体種類
  • ジェスチャーの発生位置などの情報を取得するには?

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

環境

Swift UIでタップや長押しなどのイベントをビューに追加する方法をまとめました。

Gesture(ジェスチャー)とは?

Web制作では「イベント」と呼ばれるクリックやホバーなどのユーザー操作ですがSwiftではGesture(ジェスチャー)と呼ばれ管理されています。

ジェスチャーにはタップや長押し、スワイプ、ピンチなど、スマホを操作する際に発生するイベントが含まれています。

Swift UIに限らず、Swiftではジェスチャーが発生した時に任意の処理を行わせる仕組みが備わっているのです。これは元々イベント処理を持っているボタンなどだけではなく、Textやラベルなど本来イベント処理を保持していないビューに対してもカスタマイズして組み込むことが可能になります。

ジェスチャーに対する処理の組み込みはSwift UIではモディファイア(メソッド)として、UIKitではGestureRecognizer(ジェスチャーレコグナイザー)クラスとして用意されています。しかし両者は別物なので取扱には注意してください。

タップされた時の処理

SwiftUIでビューがタップされた時に任意の処理をさせるにはonTapGestureモディファイアを使用します。

定義

func onTapGesture(
    count: Int = 1,
    perform action: @escaping () -> Void
) -> some View

引数:count

引数countにはタップ回数を指定します。デフォルト値として1が渡されているので省略すると1回のタップで発火します。

引数:perform

引数performにはイベント発生時に実行させたい処理を渡します。

引数の最後が@escapingのついたクロージャなのでTrailing Closure記法を使って引数名を省略して記述することができます。

使用例

Text("ボタン").onTapGesture {
  print("タップされたよ")
}

ダブルタップの検知

ダブルタップを検知して処理を発火させるには引数countの値を2にするだけです。

Text("ボタン").onTapGesture(count: 2) {
    print("ダブルタップされたよ")
}

引数に渡す数値を変更するだけでタップ数が任意の数行われた場合のみ処理を実行する機能を作ることも可能です。

長押しされた時の処理

ビューを長押しされた時に処理を発火させたい場合はonLongPressGestureモディファイアを使用します。

定義

func onLongPressGesture(
    minimumDuration: Double = 0.5,
    perform action: @escaping () -> Void,
    onPressingChanged: ((Bool) -> Void)? = nil
) -> some View

引数:minimumDuration

引数minimumDurationには長押しと判別する時間を浮動小数点数型で指定します。デフォルト値は0.5となっており、省略可能です。短すぎる時間と指定すると長押しとは言えなくなってしまうので注意してください。

引数:perform

引数performには長押しで実行される処理を指定します。

引数:onPressingChanged

引数onPressingChangedには状態変化時(押された時と離された時)に行うクロージャを指定します。クロージャの引数から現在の状態を真偽値で取得できます。

使用例

Text("ボタン").onLongPressGesture() {
    print("長押しされたよ")
}

Swift UIでのモディファイアを使ったジェスチャー管理

Swift UIでのジェスチャー管理はview構造体(プロトコル)のメソッド(モディファイア)として提供されていることがわかったと思いますが実はモディファイアで指定する方法には2種類あります。

1:ジェスチャー専用のモディファイア

1つ目の方法はonTapGestureonLongPressGestureといった各ジェスチャーに対応したView構造体のモディファイアを呼び出す方法です。

Text("ボタン").onTapGesture {
  print("タップされたよ")
}

View構造体から呼び出せるメソッドに関しては公式サイトをご確認ください。

2:ジェスチャーモディファイアにジェスチャー構造体を指定する

2つ目はgestureメソッドを使用する方法です。例えば1つ目と同じタップジェスチャーを取得する場合は以下のようになります。

struct ContentView: View {
    let tap = TapGesture()
        .onEnded { _ in
            print("タップされたよ")
        }
    var body: some View {
        Text("ボタン").gesture(tap)
    }
}

gestureメソッドの使い方

gestureメソッドは引数に各ジェスチャー(イベント)型の構造体を渡して使用します。

func gesture<T>(
    _ gesture: T,
    including mask: GestureMask = .all
) -> some View where T : Gesture

引数gestureGestureプロトコルに準拠したジェスチャー構造体を指定します。

ジェスチャー構造体の種類

ジェスチャー構造体 概要
AnyGesture タイプ消去ジェスチャー?
DragGesture ドラッグ
ExclusiveGesture 2つのジェスチャを保持しどちらかを実行
GestureStateGesture ジェスチャの状態を更新
LongPressGesture 長押し
MagnificationGesture 拡大動作(拡大量を検知)
RotationGesture 回転モーション(回転の角度を検知)
SequenceGesture 2つのジェスチャを保持し直列に実行
SimultaneousGesture 2つのジェスチャを保持し同時に実行
SpatialTapGesture タップ(場所を検知)
TapGesture タップ

SimultaneousGestureを使用して画面遷移時に任意の処理を挟む方法を紹介しています。

Gestureプロトコル

各構造体はGestureプロトコルに準拠しており、以下のようなメソッドを保持しています。

associatedtype Value
func onChanged(_ action: @escaping (Self.Value) -> Void) -> _ChangedGesture<Self>
func onEnded(_ action: @escaping (Self.Value) -> Void) -> _EndedGesture<Self>

onChangedメソッド

onChangedメソッドはジェスチャの値が変化したときに実行する処理を渡せるメソッドです。TapGestureなどでは呼び出すことができませんがDragGestureなどでは使用可能です。

onEndedメソッド

onEndedメソッドはジェスチャの終了時に実行する処理を渡せるメソッドです。

例えばこの2つのメソッドを組み合わせてビューをスワイプしている間とスワイプ後に指を離したタイミングに処理を組み込むこともできます。

struct ContentView: View {
    let drag = DragGesture()
        .onChanged { _ in
            print("スワイプ中")
        }
        .onEnded { _ in
            print("スワイプ終了")
        }
    var body: some View {
        Text("ボタン").gesture(drag)
    }
}

Valueから取得できる情報

Valueにはジェスチャー型ごとに保持する情報が格納されます。引数に渡したジェスチャーによって保持する情報が異なるので注意してください。

struct ContentView: View {
    let drag = DragGesture()
        .onEnded {value in
            dump(value)
        }
    var body: some View {
        Text("ボタン").gesture(drag)
    }
}

例えばDragGestureの場合は以下の通りです。

struct DragGesture.Value {
    var location: CGPoint
    // ドラッグジェスチャの現在のイベントの場所
    var predictedEndLocation: CGPoint
    // 現在のドラッグ速度に基づいた、ドラッグが停止した場合の最終的な位置の予測
    var predictedEndTranslation: CGSize
    // 現在のドラッグ速度に基づいた、ドラッグが停止した場合の最終的な移動の予測
    var startLocation: CGPoint
    // ドラッグジェスチャの最初のイベントの場所
    var time: Date
    // ドラッグジェスチャの現在のイベントに関連付けられた時間
    var translation: CGSize
    // ドラッグジェスチャの開始からドラッグジェスチャの現在のイベントまでの合計変換
}

このようにジェスチャの発生位置や経過時間などがValueから取得できます。

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

私がSwift UI学習に使用した参考書

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index