简体   繁体   English

SwiftUI:在 LazyVGrid 中遇到拖放问题

[英]SwiftUI: Running into issues with Drag and Drop inside a LazyVGrid

I've been working on my own smart home app and have run into some issues when trying to build the grid for the app.我一直在开发自己的智能家居应用程序,并在尝试为应用程序构建网格时遇到了一些问题。

I've been basing this home app on this tutorial.我一直将这个家庭应用程序建立在本教程的基础上。 The goal is that one can reorder the individually sized blocks in the grid basically like he or she wants.目标是人们可以基本上按照他或她的需要重新排列网格中单独大小的块。 The blocks(items) represent different gadgets in the smart home application.块(项目)代表智能家居应用程序中的不同小工具。 The issue I'm facing is that I can't seem to get the drag & drop to work.我面临的问题是我似乎无法让拖放工作。 Maybe it's better to put all the item views in one custom view and then run a "ForEach" loop for them so that the.onDrag works?也许最好将所有项目视图放在一个自定义视图中,然后为它们运行“ForEach”循环以便.onDrag 工作? I'm relatively new to SwiftUI so I appreciate every hint I can get this program to work.我对 SwiftUI 比较陌生,所以我很感激我可以让这个程序工作的每一个提示。

Here is my code:这是我的代码:

ItemModel1:产品型号1:

struct ItemModel: Identifiable, Equatable {
let id: String
var title: String

init(id: String = UUID().uuidString, title: String) {
    self.id = id
    self.title = title

    }

    func updateCompletion() -> ItemModel {
        return ItemModel(id: id, title: title)
    }
    }

ItemModel2:产品型号2:

    struct ItemModel2: Identifiable, Equatable {
        let id: String
        var title: String
        
        init(id: String = UUID().uuidString, title: String) {
            self.id = id
            self.title = title

    }

    func updateCompletion() -> ItemModel2 {
        return ItemModel2(id: id, title: title)
    }
    }

It's essentially the same for the two other ItemModels 3 and 4..其他两个 ItemModel 3 和 4 基本相同。

ItemViewModel:项目视图模型:

    class ItemViewModel {
        var items: [ItemModel] = []
        @Published var currentGrid: ItemModel?
        
        init() {
            getItems()
        }
        
        func getItems() {
            let newItems = [
                ItemModel(title: "Item1"),
            ]
            items.append(contentsOf: newItems)
        }
        
        func addItem(title: String) {
            let newItem = ItemModel(title: title)
            items.append(newItem)
        }
        
        func updateItem(item: ItemModel) {
            
            if let index = items.firstIndex(where: { $0.id == item.id}) {
                items[index] = item.updateCompletion()
            }
        }
    }

ContentView:内容视图:

        struct DropViewDelegate: DropDelegate {
           
            var grid: ItemModel
            var gridData: ItemViewModel
            

            
            func performDrop(info: DropInfo) -> Bool {

                return true
            }
            
            func dropEntered(info: DropInfo) {

                let fromIndex = gridData.items.firstIndex { (grid) -> Bool in
                    return self.grid.id == gridData.currentGrid?.id
                } ?? 0
                
                let toIndex = gridData.items.firstIndex { (grid) -> Bool in
                    return self.grid.id == self.grid.id
                } ?? 0
                
                if fromIndex != toIndex{
                    withAnimation(.default){
                        let fromGrid = gridData.items[fromIndex]
                        gridData.items[fromIndex] = gridData.items[toIndex]
                        gridData.items[toIndex] = fromGrid
                    }
                }
            }
            

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



        struct ContentView: View {
            @State var items: [ItemModel] = []
            @State var items2: [ItemModel2] = []
            @State var items3: [ItemModel3] = []
            @State var items4: [ItemModel4] = []
            @State var gridData = ItemViewModel()
            
            let columns = [
                GridItem(.adaptive(minimum: 160)),
                GridItem(.adaptive(minimum: 160)),
            ]
            let columns2 = [
                GridItem(.flexible()),
            ]
            
            
            var body: some View {
                ZStack{
                    ScrollView{
                        VStack{
                            HStack(alignment: .top){
                                
                                Button(action: saveButtonPressed, label: {
                                    Text("Item1")
                                        .font(.title2)
                                                                
                           .foregroundColor(.white)
                                })
                                Button(action: saveButtonPressed2, label: {
                                    Text("Item2")
                                        .font(.title2)
                                                                
                           .foregroundColor(.white)
                                })
                                Button(action: saveButtonPressed3, label: {
                                    Text("Item3")
                                        .font(.title2)
                                                                
                             .foregroundColor(.white)
                                })
                                Button(action: saveButtonPressed4, label: {
                                    Text("Item4")
                                        .font(.title2)
                                                               
                         .foregroundColor(.white)
                                })
                                
                            }
                            
                            
                            
                            LazyVGrid(
                                columns: columns,
                                alignment: .leading,
                                spacing: 12
                            ){
                                ForEach(items) { item in
                                    Item1View (item: item)
                                    if 1 == 1 { Color.clear }
                                }
                                
                                ForEach(items4) { item4 in
                                    Item4View (item4: item4)
                                    if 1 == 1 { Color.clear }
                                }
                                
                                ForEach(items2) { item2 in
                                    Item2View (item2: item2)
                                }
                                LazyVGrid(
                                    columns: columns2,
                                    alignment: .leading,
                                    spacing: 12
                                ){
                                    ForEach(items3) { item3 in
                                        Item3View (item3: item3)
                                    }
                                }
                            }
                            .onDrag({
                            self.gridData = items
                            return NSItemProvider(item: nil, typeIdentifier: 
                          self.grid)
                            })
                            .onDrop(of: [items], delegate: DropViewDelegate(grid: 
                         items, gridData: gridData))
                     
                     
                        }
                    }
                }
            }
            
            func saveButtonPressed() {
                addItem(title: "Hello")
            }
            
            func addItem(title: String) {
                let newItem = ItemModel(title: title)
                items.append(newItem)
            }
            func saveButtonPressed2() {
                addItem2(title: "Hello")
            }
            
            func addItem2(title: String) {
                let newItem = ItemModel2(title: title)
                items2.append(newItem)
            }
            func saveButtonPressed3() {
                addItem3(title: "Hello")
            }
            
            func addItem3(title: String) {
                let newItem = ItemModel3(title: title)
                items3.append(newItem)
            }
            func saveButtonPressed4() {
                addItem4(title: "Hello")
            }
            
            func addItem4(title: String) {
                let newItem = ItemModel4(title: title)
                items4.append(newItem)
            }
            
            
            
            struct ContentView_Previews: PreviewProvider {
                static var previews: some View {
                    ContentView()
                }
            }
            
        }

Item1:项目1:

            struct Item1View: View {
               @State var item: ItemModel

            var body: some View {
                
                    HStack {
                        Text(item.title)
                    }
                    .padding( )
                    .frame(width: 396, height: 56)
                    .background(.black)
                    .cornerRadius(12.0)

            }
            }

Item2:项目2:

            struct Item2View: View {
               @State var item2: ItemModel2

            var body: some View {
                
                    HStack {
                        Text(item2.title)
                    }
                    .padding( )
                    .frame(width: 182, height: 132)
                    .background(.black)
                    .cornerRadius(12.0)

            }
            }

Item3:第 3 项:

            struct Item3View: View {
               @State var item3: ItemModel3

            var body: some View {
                
                    HStack {
                        Text(item3.title)
                    }
                    .padding( )
                    .frame(width: 182, height: 62)
                    .background(.black)
                    .cornerRadius(12.0)

            }
            }

Item4:第 4 项:

            struct Item4View: View {
               @State var item4: ItemModel4

            var body: some View {
                
                    HStack {
                        Text(item4.title)
                    }
                    .padding( )
                    .frame(width: 396, height: 156)
                    .background(.black)
                    .cornerRadius(12.0)

            }
            }

I tried recreating the grid Asperi linked.我尝试重新创建 Asperi 链接的网格。 However, the.onDrop doesn't seem to work like it should.但是, the.onDrop 似乎并没有像它应该的那样工作。 The drop only occurs after you pressed another item to drag it.仅在您按下另一个项目以拖动它后才会发生下降。 Only then will the previous items reorder themselves..只有这样,以前的项目才会重新排序。

My version:我的版本:

import SwiftUI
import UniformTypeIdentifiers

struct ItemModel6: Identifiable, Equatable {
let id: String
var title: String

init(id: String = UUID().uuidString, title: String) {
    self.id = id
    self.title = title

}

func updateCompletion() -> ItemModel6 {
return ItemModel6(id: id, title: title)
}
}



class Model: ObservableObject {
var data: [ItemModel6] = []

let columns = [
    GridItem(.adaptive(minimum: 160)),
    GridItem(.adaptive(minimum: 160)),
]

init() {
    data = Array(repeating: ItemModel6(title: "title"), count: 
    100)
    for i in 0..<data.count {
        data[i] = ItemModel6(title: "Hello")
    }
    }
    }



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

@State private var dragging: ItemModel6?

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

            }
        }.animation(.default, value: model.data)
    }
    .onDrop(of: [UTType.text], delegate: 
   DropOutsideDelegate(current: $dragging))
    }
}
struct DropOutsideDelegate: DropDelegate {
@Binding var current: ItemModel6?
    
func performDrop(info: DropInfo) -> Bool {
    current = nil
    return true
}
    }

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

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



struct GridItemView: View {
@State var item2: ItemModel6

    var body: some View {
 
     HStack {
         Text(item2.title)
     }
     .padding( )
     .frame(width: 182, height: 132)
     .background(.gray)
     .cornerRadius(12.0)

    }
}


struct DemoDragRelocateView_Previews: PreviewProvider {
static var previews: some View {
    DemoDragRelocateView()
        .preferredColorScheme(.dark)
}
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM