DragGestureの使い方

DragGestureは、画面上を指でドラッグした時の操作を検出するためのGestureです。例えば、次のような操作を実装できます。

  • 図形を指で移動させる
  • スライダーを動かす
  • カードをスワイプする
  • ドラッグした距離を取得する

基本的には、DragGesture()と.gesture()を組み合わせて使用します。

1.DragGestureの基本構文

Drag Gestureの基本的な書き方は次のようになります。

struct ContentView: View {
     var body: some View {
         Circle()
              .fill(.blue)
              .frame(width: 100, height: 100)
              .gesture(
                    DragGesture()
              )
    }
}

Circle()に対して、

.gesture(
     DragGesture()
)

を指定しています。

これによってCircleにドラッグ操作を設定できます。

ただし、この段階ではドラッグを検出するだけなので、Circleが実際に動くわけではありません。

ドラッグ中に処理を実行するには.onChangedを使用します。

2..onChangedによる移動中の処理

.onChangedは、ドラッグ操作中に繰り返し呼び出されます。

基本構文は次のようになります。

DragGesture()
     .onChanged { value in
             // ドラッグ中の処理
   }

valueには、現在ドラッグ操作に関する情報が入っています。

例えば、ドラッグ中の指の位置を確認する場合はlocationを利用できます。

struct ContentView: View {
      var body: some View {
            Circle()
                .fill(.blue)
                .frame(width: 100, height: 100)
                .gesture(
                       DragGesture()
                           .onChanged { value in
                                print(value.location)
                           }
                )
       }
}

Circleをドラッグすると、指が移動するたびに現在位置が出力されます。

例えば、

(120.0、250.0)

(125.0、253.0)

(130.0、257.0)

のように位置が変化していきます。

.onChangedは、「指を動かしている途中の処理」を実装する時に使用すると覚えると分かりやすいでしょう。

3..onEndedによる指を離した時の処理

.onEndedは、ドラッグ操作が終了した時に呼び出されます。

つまり、ドラッグしていた指を画面から離した瞬間に処理を実行できます。

DragGesture()
      .onEnded { value in
         // ドラッグ終了時の処理
     }

例えば次のように書けます。

struct ContentView : View {
      var body: some View {
          Circle()
              .fill(.blue)
              .frame(width: 100, height: 100)
              .gesture(
                     DragGesture()
                         .onChanged { value in
                                print("ドラッグ中")
                         }
                         .onEnded { value in
                               print("ドラッグ終了")
                         }
              )
    }
}

ドラッグ中は.onChangedが繰り返し実行され、指を離すと.onEndedが実行されます。イメージすると、

ドラッグ開始

   ↓

.onChanged

   ↓

.onChanged

   ↓

.onChanged

   ↓

指を離す

   ↓

.onEnded

という流れになります。

4.translationを利用して移動量を取得する

DragGestureで特に重要なのがtranslationです。

translationを使うと、

「ドラッグを開始した場所から、どれだけ移動したか」

を取得できます。

value.translation

translationには横方向と縦方向の移動量があります。

value.translation.width
value.translation.height

widthが横方向(X方向)、heightが縦方向(Y方向)の移動量です。

例えば、

DragGesture()
      .onChanged { value in
           print(value.translation.width)
           print(value.translation.height)
      }

とすると、ドラッグした距離を取得できます。

右方向へ100ポイント移動した場合、

value.translation.width

は、およそ100になります。

左方向ならマイナスになります。

同じように、下方向に移動するとheightはプラス、上方向ならマイナスになります。

5.Circleを実際にドラッグした動かす。

ここまでの内容を使って、Circleを指だ自由に動かしてみましょう。

struct ContentView: View {
      @State private var offset: CGSize = .zero
    var body: some View {
        Circle()
              .fill(.blue)
              .frame(width: 100, height: 100)
              .offset(offset)
              .gesture(
                     DragGesture()
                         .onChanged { value in
                                offset = value.translation
                         }
                         .onEnded { value in
                                offset = .zero
                        }
             )
     }
}

ポイントは次の部分です。

@State private var offset: CGSize = .zero

Circleの移動量を保存するためにCGSize型の変数を用意しています。

そして.onChangedの中で、

offset = value.translation

としています。

ドラッグした移動量をoffsetに代入し、

.offset(offset)

によってCircleの表示位置を変更しています。

そのため、指の動きに合わせてCircleが移動します。

6.指を離すと元の位置に戻す

先ほどのコードでは.onEndedに、

.onEnded { value in
      offset = .zero
}

と書いています。

.zeroは、

CGSize(width: 0, height: 0)

と同じ意味です。

そのため、指を離すとCircleの移動量が0になり、元の位置に戻ります。

このように、

.onChanged

でドラッグ中の位置を変更し、

.onEnded

でドラッグ終了後の動作を指定する、

という組み合わせはDragGestureの基本的な使い方になります。

7.translationとlocationの違い

DragGestureを使う時に混同しやすいのがtranslationとlocationです。

locationは現在の指の位置を表します。

value.location

一方、translationはドラッグ開始地点からの移動量を表します。

value.translation

例えば、X座標100の場所からドラッグを開始し、X座標150まで移動した場合、

location.x. → 150

translation.width  → 50

となります。

「指が現在どこにあるか」を知りたい場合はlocation、「最初の場所からどれだけ動いたか」を知りたい場合は translatiolnと考えると分かりやすいでしょう。

まとめ

DragGestureは、SWiftUIでドラッグ操作を実装する時に使用するGestureです。

基本的な流れは、

DragGesture()
       .onChanged { value in
            // ドラッグ中
     }
       .onEnded { value in
            // ドラッグ終了
     }

となります。

特に覚えておきたいのがtranslationです。

value.translation.width
value.translation.height

を利用することで、ドラッグ開始地点からどれだけ移動したのかを取得できます。まずはCircleなどの簡単なViewを、

.offset(value.translation)

の考え方を使って動かしてみると、DragGestureの仕組みを理解しやすくなります。

コメント

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