SwiftUI |使用onDrag和onDrop对单个LazyGrid中的项目重新排序? [英] SwiftUI | Using onDrag and onDrop to reorder Items within one single LazyGrid?

查看:785
本文介绍了SwiftUI |使用onDrag和onDrop对单个LazyGrid中的项目重新排序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道是否可以使用 View.onDrag View.onDrop 添加拖动和


尽管我能够使用 onDrag拖动每个项目,但是否可以在一个 LazyGrid 中手动重新排序?


code>,我不知道如何实现删除部分。



这是我正在尝试的代码:

  import SwiftUI 

/ / MARK:-数据

结构数据:可识别的{
let id:Int
}

// MARK:-模型

类模型:ObservableObject {
@已发布的var数据:[数据]

让列= [
GridItem(.fixed(160)),
GridItem (.fixed(160))
]

init(){
data = Array< Data>(重复:Data(id:0),计数:100)
for i in 0 ..< data.count {
data [i] = Data(id:i)
}
}
}

// MARK:-网格

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

var正文:某些视图{
ScrollView {
LazyVGrid(列:model.columns,间距:32){
ForEach(model.data){d在
ItemView(d :d)
.id(d.id)
.frame(宽度:160,高度:240)
.background(Color.green)
.onDrag {return NSItemProvider(对象:String(d.id)as NSString)}
}
}
}
}
}

// MARK:- GridItem

struct ItemView:View {
var d:Data

var body:some View {
VStack {
Text(String( d.id))
.font(.headline)
.foregroundColor(.white)
}
}
}

解决方案

SwiftUI 2.0


完成了可能方法的简单演示(没有进行太多调整,因为代码像演示一样快速增长)。



重要的一点是:a)重新排序不假定等待下降,因此应实时跟踪; b)为避免与坐标共舞,处理逐格项目视图更简单; c)找到要移动的内容并在数据模型中执行此操作,以便SwiftUI自己对视图进行动画处理。


通过Xcode 12b3 / iOS 14测试

 导入SwiftUI 
导入UniformTypeIdentifiers

struct GridData:可识别的,相等的{
let id:Int
}

// MARK:-模型

类模型:ObservableObject {
@已发布的var数据:[GridData]

让列= [
GridItem(.fixed(160)),
GridItem(.fixed(160))
]

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

//标记:-网格

结构DemoDragRelocateView:视图{
@StateObject private var model = Model()

@State private var dragging:GridData?

var主体:某些视图{
ScrollView {
LazyVGrid(列:model.columns,间距:32){
ForEach(model.data){d
GridItemView(d:d)
.overlay(dragging?.id == d.id?Color.white.opacity(0.8):Color.clear)
.onDrag {
self.dragging = d
返回NSItemProvider(object:String(d.id)as NSString)
}
.onDrop(of:[UTType.text],委托:DragRelocateDelegate(item: d,listData:$ model.data,当前:$ dragging))
}
} .animation(.default,value:model.data)
}
}
}

结构DragRelocateDelegate:DropDelegate {
let项:GridData
@Binding var listData:[GridData]
@Binding var当前:GridData?

func dropEntered(info:DropInfo){
如果item!= current {
let from = listData.firstIndex(of:current!)!
让我们= 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.current = nil
return true
}
}

// MARK:-GridItem

结构GridItemView:View {
var d:GridData

var body:some View {
VStack {
Text(String(d.id))
。 font(.headline)
.foreColorColor(.white)
}
.frame(宽度:160,高度:240)
.background(Color.green)
}
}


I was wondering if it is possible to use the View.onDrag and View.onDrop to add drag and drop reordering within one LazyGrid manually?

Though I was able to make every Item draggable using onDrag, I have no idea how to implement the dropping part.

Here is the code I was experimenting with:

import SwiftUI

//MARK: - Data

struct Data: Identifiable {
    let id: Int
}

//MARK: - Model

class Model: ObservableObject {
    @Published var data: [Data]
    
    let columns = [
        GridItem(.fixed(160)),
        GridItem(.fixed(160))
    ]
    
    init() {
        data = Array<Data>(repeating: Data(id: 0), count: 100)
        for i in 0..<data.count {
            data[i] = Data(id: i)
        }
    }
}

//MARK: - Grid

struct ContentView: View {
    @StateObject private var model = Model()
    
    var body: some View {
        ScrollView {
            LazyVGrid(columns: model.columns, spacing: 32) {
                ForEach(model.data) { d in
                    ItemView(d: d)
                        .id(d.id)
                        .frame(width: 160, height: 240)
                        .background(Color.green)
                        .onDrag { return NSItemProvider(object: String(d.id) as NSString) }
                }
            }
        }
    }
}

//MARK: - GridItem

struct ItemView: View {
    var d: Data
    
    var body: some View {
        VStack {
            Text(String(d.id))
                .font(.headline)
                .foregroundColor(.white)
        }
    }
}

Thank you!

解决方案

SwiftUI 2.0

Here is completed simple demo of possible approach (did not tune it much, `cause code growing fast as for demo).

Important points are: a) reordering does not suppose waiting for drop, so should be tracked on the fly; b) to avoid dances with coordinates it is more simple to handle drop by grid item views; c) find what to where move and do this in data model, so SwiftUI animate views by itself.

Tested with Xcode 12b3 / iOS 14

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 DemoDragRelocateView: View {
    @StateObject private var model = Model()

    @State private var dragging: GridData?

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

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

    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.current = nil
        return true
    }
}

//MARK: - GridItem

struct GridItemView: View {
    var d: GridData

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

这篇关于SwiftUI |使用onDrag和onDrop对单个LazyGrid中的项目重新排序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆