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の仕組みを理解しやすくなります。

コメント