Contents
DragGesture
@available(iOS 13.0, macOS 10.15, watchOS 6.0, *) @available(tvOS, unavailable) public struct DragGesture : Gesture { public struct Value : Equatable { public var time: Date public var location: CGPoint public var startLocation: CGPoint public var translation: CGSize { get } public var predictedEndLocation: CGPoint { get } public var predictedEndTranslation: CGSize { get } public static func == (a: DragGesture.Value, b: DragGesture.Value) -> Bool } public var minimumDistance: CGFloat public var coordinateSpace: CoordinateSpace public init(minimumDistance: CGFloat = 10, coordinateSpace: CoordinateSpace = .local) public typealias Body = Never } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) public protocol Gesture { associatedtype Value associatedtype Body : Gesture var body: Self.Body { get } } @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) extension Gesture { public func onEnded(_ action: @escaping (Self.Value) -> Void) -> _EndedGesture< Self > } @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) extension Gesture where Self.Value : Equatable { public func onChanged(_ action: @escaping (Self.Value) -> Void) -> _ChangedGesture< Self > }
DragGestureのinitializeを見ると、お馴染みのminimumDistanceとcoordinateSpaceがある
デフォルトで10、.localとあるので特に引数指定しなくても問題なし。
DragGesture()
DragGestureはGestureプロトコルを継承している。
そのため、Gestureプロトコルに定義しているメソッドなどを使用することができるわけで、
定義を見ると、onEndedやonChangeメソッドが定義されている。
public func onEnded(_ action: @escaping (Self.Value) -> Void) public func onChanged(_ action: @escaping (Self.Value) -> Void)
それぞれ、メソッドの定義としては、Self.ValueつまりGestureプロトコルのValueプロパティ情報を受け取り、戻り値はVoidなので、
valueの値を受け取りつつ、その値で何らかの処理を実行するイメージにある。戻り値はないので、特に返すなどせず、
ドラッグしている間とか、最後にどんな処理をするかを記載することになる。
DragGesture().onChanged({ val in })
さらに、onChangedやonEndedは、メソッドの戻り値がselfつまり、Gesture型になるので、
メソッドチェーンのように書ける。
DragGesture() .onChanged({ val in }) .onEnded({ val in })
さらに、DragGestureはViewプロトコルではないので、
some view{}にはかけません。
次にどこに記載するかについて話したいと思います。
DragGestureはGestureプロトコルなのでどこに記載する
以下のような最初のコードのsome Viewの中には直で記載できない。
DragGesture()自体は、ViewではなくGestureプロトコルを返すため、エラーになる。
struct ContentView:View{ var body: some View { } }
ではどうするか?
以下2つの書き方があるかなと思います。
- 1. var gesture: some Gesture{}のように記載する。
- 2. モディファイアgestureに記載する。
1. var gesture: some Gesture{}のように記載する。
struct DragGestureView: View { @State var isDragging = false var drag: some Gesture { DragGesture() .onChanged { _ in self.isDragging = true } .onEnded { _ in self.isDragging = false } } var body: some View { Circle() .fill(self.isDragging ? Color.red : Color.blue) .frame(width: 100, height: 100, alignment: .center) .gesture(drag) } }
上はswiftuiの定義コードですが、
GestureとViewの部分を分けて、作成しています。
2. モディファイアgestureに記載する。
.gestureモディファイアの定義を見ると、戻り値はGesture。
なので、DragGesture()を指定することが可能。
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) extension View { public func gesture< T >(_ gesture: T, including mask: GestureMask = .all) -> some View where T : Gesture }
ジェネリクスにはwhereから、Gestureプロトコルに従っている型なので、DragGesture型を採用できる。これにより、以下のようにかける。DragGesture型でreturnしているのでOK
Image("apple") .gesture( DragGesture().onChanged { value in // ドラッグ中の処理 self.location = "\(value.location)" self.translation = "\(value.translation)" }.onEnded { value in // ドラッグ終了時の処理 self.location = "\(value.location)" self.translation = "\(value.translation)" } }
Value
プロパティ | 説明 |
---|---|
time | ドラッグジェスチャの現在のイベントに関連付けられた時間。 |
location | ドラッグジェスチャの現在のイベントの位置。 |
startLocation | ドラッグジェスチャーの最初のイベントの位置。 |
translation | ドラッグジェスチャの開始からイベントまでの合計移動量。 ドラッグジェスチャの現在のイベント。 これは `location.{x,y} - startLocation.{x,y}` と等価である。 |
predictedEndLocation | 現在のドラッグ速度に基づく、最終的な位置の予測。 今ドラッグを止めた場合の位置。 |
predictedEndTranslation | 現在のドラッグ速度から予測される、最終的なもし今ドラッグを止めた場合 |