> For the complete documentation index, see [llms.txt](https://lochiwei.gitbook.io/ios/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lochiwei.gitbook.io/ios/swiftui/gestures/drag/.draggable.md).

# .draggable()

[SwiftUI](/ios/swiftui.md) ⟩ [Gestures](/ios/swiftui/gestures.md) ⟩ [Drag](/ios/swiftui/gestures/drag.md) ⟩ .draggable()

{% tabs %}
{% tab title="🌀 View+ .draggable()" %}

```swift
import SwiftUI

// 👔 Draggable
struct Draggable: ViewModifier {
    
    // 🔸 此變數目前沒什麼用，但在其他狀況下，也許可派上用場。
    @State var isDragging = false
    
    // 🔸 拖曳時，offset 會隨時更新，但 dragOffset 保持不變。
    //    沒拖曳時，兩者是一樣的。
    @State private var offset = CGSize.zero        // current offset
    @State private var dragOffset = CGSize.zero    // prev accumulative offset
    
    // ⭐️ optional event handlers
    typealias OffsetHandler = (CGSize) -> Void
    var onChanged: OffsetHandler?
    var onEnded  : OffsetHandler?
    
    func body(content: Content) -> some View {
        content
            .offset(offset)        // ⭐️ apply offset
            .gesture(
                DragGesture()
                    .onChanged { value in
                        isDragging = true
                        // update offset
                        offset = dragOffset + value.translation
                        // event handler
                        onChanged?(offset)
                    }
                    .onEnded { value in
                        isDragging = false
                        // update offset
                        offset = dragOffset + value.translation
                        // ⭐️ save accumulative offset
                        dragOffset = offset
                        // event handler
                        onEnded?(offset)
                    }
            )
    }
}

// 🌀 View+ .draggable()
extension View {
    /// `view.draggable(onChanged:onEnded:)`
    func draggable(
        onChanged: Draggable.OffsetHandler? = nil, 
        onEnded  : Draggable.OffsetHandler? = nil
    ) -> some View {
        modifier(Draggable(onChanged: onChanged, onEnded: onEnded))
    }
}
```

{% endtab %}

{% tab title="👁️ 預覽" %}
{% embed url="<https://youtu.be/fcNPtYRCsAA>" %}

⬆️ 需要： [view + .frame()](/ios/swiftui/view/layout/frame/ext.md), [HandlePoint](/ios/swiftui/gestures/drag/.draggable/handlepoint.md)

```swift
import SwiftUI

struct TestDraggable: View {
    var body: some View {
        VStack {
            Group {
                HandlePoint()       // 🖼 HandlePoint
                Color.pink
                    .frame(50)      // 🌀 View+ .frame()
                    .draggable()    // 👔 Draggable
                Capsule()
                    .frame(200, 50) // 🌀 View+ .frame()
                    .foregroundColor(.blue)
                    .draggable()    // 👔 Draggable
            }
            .border(.secondary)
        }
    }
}

struct TestDraggable_Previews: PreviewProvider {
    static var previews: some View {
        TestDraggable()
    }
}
```

{% endtab %}

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

* Vasilis Akoinoglou ⟩ [Making a Bézier Curve Editor in SwiftUI](https://alladinian.hashnode.dev/making-a-bezier-curve-editor-in-swiftui) ⭐️
  {% endtab %}

{% tab title="⬇️ 應用" %}

* [HandlePoint](/ios/swiftui/gestures/drag/.draggable/handlepoint.md) - draggable point.
  {% endtab %}

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

* is [ViewModifier](/ios/swiftui/view/modifier/viewmodifier.md).
  {% endtab %}
  {% endtabs %}
