Article

Composing SwiftUI Gestures

Combine gestures to create complex interactions. ジェスチャそれらを結合して複雑な相互作用を作成します。

Overview 概要

When you add multiple gestures to your app’s view hierarchy, you need to decide how the gestures interact with each other. You use gesture composition to define the order SwiftUI recognizes gestures. There are three gesture composition types: あなたが複数のジェスチャをあなたのアプリのもつビュー階層に加える場合、あなたはどのようにジェスチャそれらがお互いと相互作用するか決定する必要があります。あなたはジェスチャ合成を使って、より古いSwiftUIが認識するジェスチャを定義します。3つのジェスチャ合成型があります:

  • Simultaneous

  • Sequenced

  • Exclusive

When you combine gesture modifiers simultaneously, SwiftUI must recognize all subgesture patterns at the same time for it to recognize the combining gesture. When you sequence gesture modifiers one after the other, SwiftUI must recognize each subgesture in order. Finally, when you combine gestures exclusively, SwiftUI recognizes the entire gesture pattern when SwiftUI only recognizes one subgesture but not the others. あなたがジェスチャ修飾子を同時に結合する場合、SwiftUIは、結合ジェスチャを認識するために、それに対して全てのサブジェスチャパターンを同時に認識する必要があります。あなたがジェスチャ修飾子を順々に並べる場合、SwiftUIはそれぞれの下位ジェスチャを順番に認識しなければなりません。最後に、あなたがジェスチャを排他的に結合する場合、SwiftUIが1つの下位ジェスチャを認識するだけで他のものをしない時にSwiftUIは全体のジェスチャパターンを認識します。

Sequence One Gesture After Another 1つのジェスチャを他のものの後に配列する

When you sequence one gesture after another, SwiftUI recognizes the first gesture before it recognizes the second. For example, to require a long press before the user can drag a view, you sequence a DragGesture after a LongPressGesture. あなたが1つのジェスチャを他のものの後に配列する場合、SwiftUIは最初のジェスチャを認識します、それが2番目のものを認識する前に。例えば、ユーザがビューをドラッグできる前に長押しを要求するには、あなたはDragGestureLongPressGestureの後に配列します。

Model Sequenced Gesture States 配列されたジェスチャ状態それらを形作る

To make it easier to track complicated states, use an enumeration that captures all of the states you need to configure your views. In the following example, there are three important states: no interaction (inactive), long press in progress (pressing), and dragging (dragging). 入り組んだ状態の追跡をより簡単にするために、ある列挙を使ってください、それはあなたのビューを構成設定するのにあなたが必要とする状態の全てをキャプチャするものです。以下の例において、3つの重要な状態があります:相互作用なし(inactive)、進行中の長押し(pressing)、そしてドラッグ(dragging)。


struct DraggableCircle: View {


    enum DragState {
        case inactive
        case pressing
        case dragging(translation: CGSize)
        
        var translation: CGSize {
            switch self {
            case .inactive, .pressing:
                return .zero
            case .dragging(let translation):
                return translation
            }
        }
        
        var isActive: Bool {
            switch self {
            case .inactive:
                return false
            case .pressing, .dragging:
                return true
            }
        }
        
        var isDragging: Bool {
            switch self {
            case .inactive, .pressing:
                return false
            case .dragging:
                return true
            }
        }
    }
    
    @GestureState var dragState = DragState.inactive
    @State var viewState = CGSize.zero

Create Gestures and Update the UI State ジェスチャを作成するそしてUI状態を更新する

When you sequence two gestures, the callbacks capture the state of both gestures. In the update callback, the new value uses an enumeration to represent the combination of the possible gesture states. The code below converts the underlying gesture states into the high-level DragState enumeration defined above. あなたが2つのジェスチャを配列する場合、コールバックは両方のジェスチャの状態をキャプチャします。更新コールバックにおいて、新しいvalueは列挙を使って可能なジェスチャ状態の組み合わせを表します。下のコードは、基礎をなすジェスチャ状態を、上で定義される高水準DragState列挙へと変換します。


var body: some View {
        let minimumLongPressDuration = 0.5
        let longPressDrag = LongPressGesture(minimumDuration: minimumLongPressDuration)
            .sequenced(before: DragGesture())
            .updating($dragState) { value, state, transaction in
                switch value {
                // Long press begins.
                case .first(true):
                    state = .pressing
                // Long press confirmed, dragging may begin.
                case .second(true, let drag):
                    state = .dragging(translation: drag?.translation ?? .zero)
                // Dragging ended or the long press cancelled.
                default:
                    state = .inactive
                }
            }
            .onEnded { value in
                guard case .second(true, let drag?) = value else { return }
                self.viewState.width += drag.translation.width
                self.viewState.height += drag.translation.height
            }

When the user begins pressing the view, the drag state changes to pressing and a shadow animates under the shape. After the user finishes the long press and the drag state changes to dragging, a border appears around the shape to indicate that the user may begin moving the view. ユーザがビューを押すことを始める時、ドラッグ状態はpressingに変わります、そして影が形状の下に生気を与えます。ユーザが長押しを終了するそしてドラッグ状態がdraggingに変化する後に、境界線が形状の周りに現れて、ユーザがビューの移動を始めるかもしれないことを指し示します。


        return Circle()
            .fill(Color.blue)
            .overlay(dragState.isDragging ? Circle().stroke(Color.white, lineWidth: 2) : nil)
            .frame(width: 100, height: 100, alignment: .center)
            .offset(
                x: viewState.width + dragState.translation.width,
                y: viewState.height + dragState.translation.height
            )
            .animation(nil)
            .shadow(radius: dragState.isActive ? 8 : 0)
            .animation(.linear(duration: minimumLongPressDuration))
            .gesture(longPressDrag)
    }
}

See Also 参照

Combined Gestures 結合されたジェスチャ