# Drag

[SwiftUI](https://lochiwei.gitbook.io/ios/swiftui) ⟩ [Gestures](https://lochiwei.gitbook.io/ios/swiftui/gestures) ⟩ [Drag](https://lochiwei.gitbook.io/ios/swiftui/gestures/drag) ⟩&#x20;

{% tabs %}
{% tab title="💾 程式" %}
{% embed url="<https://youtu.be/hqAkLOkshKY>" %}

⬆️ 需要： [vector2d](https://lochiwei.gitbook.io/ios/custom/package/geometrykit/vector2d "mention")

📗 參考：[Mastering SwiftUI](https://www.appcoda.com/swiftui/), Ch. 17: Using Gestures (p.374)

```swift
import SwiftUI

struct StarView: View {
    
    // ⭐️ `@GestureState`: tracks gesture's state
    // • will reset to original value when gesture ends❗
    // • need another @State property to save final state❗
    typealias DragState = (offset: CGSize, isDragging: Bool)
    @GestureState private var dragState: DragState = (.zero, false)
    
    // ⭐️ save final drag state
    @State private var viewOffset = CGSize.zero
    
    // view body
    var body: some View {
        Image(systemName: "star.circle.fill") 
            .font(.system(size: 100))
            .border(.secondary)
            .overlay(overlay)
            .offset(totalOffset)    // ⭐️ apply offset
            .foregroundColor(dragState.isDragging ? .pink : .yellow)
            .gesture(drag)          // ⭐️ drag gesture
    }
    
    /// ⭐️ drag gesture
    var drag: some Gesture {
        DragGesture() 
            // ⭐️ update @GestureState property
            // • value: DragGesture.Value (current drag gesture's value)
            // • state: @GestureState property
            // • transaction: Transaction (ignored)
            .updating($dragState) { value, state, _ in
                // ⭐️ update `dragState`
                state.offset = value.translation
                state.isDragging = true
            }
            .onEnded { value in
                // ⭐️ when drag ends, `dragState` will reset.
                // ⭐️ save final drag total translation to `viewOffset`
                viewOffset += value.translation    // 🅿️ Vector2D
            }
    }
    
    /// view's offset + drag's offset
    var totalOffset: CGSize {
        viewOffset + dragState.offset    // 🅿️ Vector2D
    }
    
    /// overlay text
    var overlay: some View {
        VStack(alignment: .leading) {
            Text(verbatim: "drag: \(dragState.offset)")
                .fixedSize()
            Text(verbatim: "view: \(viewOffset)")
                .fixedSize()
            Text(verbatim: "drag + view: \(totalOffset)")
                .fixedSize()
        }
        .foregroundColor(.secondary)
        .offset(y: -110)
    }
}
```

{% endtab %}

{% tab title="💈範例" %}

* [longpressdrag](https://lochiwei.gitbook.io/ios/swiftui/gestures/combine/sequenced/longpressdrag "mention")
  {% endtab %}

{% tab title="📗 參考" %}

* [x] [Mastering SwiftUI](https://www.appcoda.com/swiftui/), Ch. 17: Using Gestures (p.374)
* [ ] Sarun ⟩ [Move your view around with Drag Gesture in SwiftUI](https://sarunw.com/posts/move-view-around-with-drag-gesture-in-swiftui/) ⭐️
* [ ] SerialCoder.dev ⟩ [Handle Press And Release Events in SwiftUI](https://serialcoder.dev/text-tutorials/swiftui/handle-press-and-release-events-in-swiftui/)\
  use [.simultaneousGesture()](https://swiftontap.com/view/simultaneousgesture\(_:including:\))
* [ ] NSScreencast ⟩ [SwiftUI Gestures](https://nsscreencast.com/episodes/400-swiftui-gestures)
  {% endtab %}

{% tab title="📘 手冊" %}

* [SwiftUI](https://developer.apple.com/documentation/swiftui) ⟩&#x20;
  * [Gestures](https://developer.apple.com/documentation/swiftui/gestures) ⟩&#x20;
    * [Gesture](https://developer.apple.com/documentation/swiftui/gesture) (<mark style="color:orange;">**protocol**</mark>)
      * [.updating(\_:body:)](https://developer.apple.com/documentation/swiftui/gesture/updating\(_:body:\))
      * [.onChanged(\_:)](https://developer.apple.com/documentation/swiftui/gesture/onchanged\(_:\))
      * [.onEnded(\_:)](https://developer.apple.com/documentation/swiftui/gesture/onended\(_:\))
    * [DragGesture](https://developer.apple.com/documentation/swiftui/draggesture) (<mark style="color:red;">**struct**</mark>)
      * [DragGesture.Value](https://developer.apple.com/documentation/swiftui/draggesture/value) (<mark style="color:red;">**struct**</mark>)&#x20;
        * [translation](https://developer.apple.com/documentation/swiftui/draggesture/value/translation) (CGSize) - total translation of the drag.
        * [location](https://developer.apple.com/documentation/swiftui/draggesture/value/location) (CGPoint) - current location of the drag.
  * [Input and Event Modifiers](https://developer.apple.com/documentation/swiftui/view-input-and-events) ⟩ [.gesture(\_:including:)](https://developer.apple.com/documentation/swiftui/view/gesture\(_:including:\))
    {% endtab %}

{% tab title="👥 相關" %}

* use [gesturestate](https://lochiwei.gitbook.io/ios/swiftui/gestures/gesturestate "mention") to track gesture's state.
  {% endtab %}
  {% endtabs %}
