👆Drag

SwiftUIGesturesDrag

⬆️ 需要: Vector2D

📗 參考:Mastering SwiftUI, Ch. 17: Using Gestures (p.374)

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)
    }
}

Last updated

Was this helpful?