SwiftUI |使用onDrag在LazyGrid中自定义Dragitem外观

时间:2020-08-22 06:00:03

标签: ios swift drag-and-drop swiftui grid

我一直想知道在preview image中使用onDrag时是否有任何方法可以自定义要拖动的项目的LazyGrid

您可能会看到,preview image保持不变,而所有其他项目都会改变其高度。 我也希望它的高度也较小。

像这样:

由于在拖动过程的开始就生成了该视图的渲染并将其用作preview image,因此在设置项目高度之前 ,我不知道如何人们会意识到这一点。

一个想法是在LongPressGesture手势之前先插入onDrag。这样,我们可以在onDrag开始之前设置高度,这将产生新高度的快照。我面临的问题是将这些手势组合在一起,使其功能像一个手势一样,而无需在它们之间释放。

也许还有另一种方法,或者我误解了某些东西?

这是完整的演示代码:

import SwiftUI
import UniformTypeIdentifiers

struct GridData: Identifiable, Equatable {
    let id: Int
}

//MARK: - Model

class Model: ObservableObject {
    @Published var data: [GridData]

    let columns = [
        GridItem(.fixed(160)),
        GridItem(.fixed(160))
    ]

    init() {
        data = Array(repeating: GridData(id: 0), count: 100)
        for i in 0..<data.count {
            data[i] = GridData(id: i)
        }
    }
}

//MARK: - Grid

struct ContentView: View {
    @StateObject private var model = Model()

    @State private var dragging: GridData?
    @State private var onDrag = false

    var body: some View {
        ScrollView {
           LazyVGrid(columns: model.columns, spacing: 32) {
                ForEach(model.data) { d in
                    GridItemView(d: d, onDrag: $onDrag)
                        .overlay(dragging?.id == d.id ? Color.white.opacity(0.8) : Color.clear)
                        .onDrag {
                            self.onDrag = true
                            self.dragging = d
                            
                            return NSItemProvider(object: String(d.id) as NSString)
                        }
                        .onDrop(of: [UTType.text], delegate: DragRelocateDelegate(item: d, listData: $model.data, current: $dragging, onDrag: $onDrag))
                }
           }
           .animation(.easeInOut(duration: 0.3), value: model.data)
        }
    }
}

//MARK: - Drag and Drop

struct DragRelocateDelegate: DropDelegate {
    let item: GridData
    @Binding var listData: [GridData]
    @Binding var current: GridData?
    @Binding var onDrag: Bool

    func dropEntered(info: DropInfo) {
        if item != current {
            let from = listData.firstIndex(of: current!)!
            let to = listData.firstIndex(of: item)!
            if listData[to].id != current!.id {
                listData.move(fromOffsets: IndexSet(integer: from),
                    toOffset: to > from ? to + 1 : to)
            }
        }
    }

    func dropUpdated(info: DropInfo) -> DropProposal? {
        return DropProposal(operation: .move)
    }

    func performDrop(info: DropInfo) -> Bool {
        self.onDrag = false
        self.current = nil
        return true
    }
}

//MARK: - GridItem

struct GridItemView: View {
    var d: GridData
    @Binding var onDrag: Bool

    var body: some View {
        VStack {
            Text(String(d.id))
                .font(.headline)
                .foregroundColor(.white)
        }
        .frame(width: 160, height: onDrag ? 140 : 240)
        .background(Color.green)
        .animation(.easeInOut(duration: 0.6))
    }
}

谢谢!

0 个答案:

没有答案