简体   繁体   English

将项目从一个列表拖到 SwiftUI 中的另一个列表

[英]Drag item from one List to another List in SwiftUI

I have two Lists each with simple items.我有两个列表,每个列表都有简单的项目。 I can rearrange items within a list, with the code shown below.我可以使用下面显示的代码重新排列列表中的项目。 I want to be able to drag an item from one list and drop it into the other list.我希望能够从一个列表中拖动一个项目并将其放入另一个列表中。 Not sure what I need to enable to make that happen.不知道我需要什么才能做到这一点。 As is, I can drag something from one list all over the screen, but I can't drop it anywhere except within its own list;照原样,我可以将一个列表中的某些内容拖到整个屏幕上,但我不能将它拖放到它自己的列表中之外的任何地方; if I release the drag anywhere else, it just flies back to its original location.如果我在其他任何地方释放阻力,它就会飞回原来的位置。

Clearly, I need to add something(s) to enable the desired behavior;显然,我需要添加一些东西来启用所需的行为; any ideas on what's required (not necessarily using .onMove -- that's within the same list) would be most appreciated.任何关于所需内容的想法(不一定使用.onMove - 在同一个列表中)将不胜感激。

struct ContentView: View {
    @State private var users1 = ["AAA", "BBB", "CCC"]
    @State private var users2 = ["DDD", "EEE", "FFF"]
    @State private var isEditable = true

    var body: some View {
        HStack {
            Spacer()
            List {
                ForEach(users1, id: \.self) { user in
                    Text(user)
                        .background(Color(.yellow))
                }
                .onMove(perform: move1)
            }
            .environment(\.editMode, isEditable ? .constant(.active) : .constant(.inactive))
            Spacer()
            List {
                ForEach(users2, id: \.self) { user in
                    Text(user)
                        .background(Color(.orange))
                }
                .onMove(perform: move2)
            }
            .environment(\.editMode, isEditable ? .constant(.active) : .constant(.inactive))
            Spacer()
        }
    }
    func move1(from source: IndexSet, to destination: Int) {
        users1.move(fromOffsets: source, toOffset: destination)
    }
    func move2(from source: IndexSet, to destination: Int) {
        users2.move(fromOffsets: source, toOffset: destination)
    }
}

I don't think this is possible with SwiftUI yet.我认为 SwiftUI 尚无法做到这一点。 This piece of code shows how you use two UITableViews .这段代码展示了如何使用两个UITableViews I hope you can improve this to achieve what you are looking for.我希望你能改进它以实现你正在寻找的东西。

First create this class which does all the magic.首先创建这个 class 来完成所有的魔法。 You need to import UIKit and MobileCoreServices .您需要导入UIKitMobileCoreServices

class TableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITableViewDragDelegate, UITableViewDropDelegate {

    var leftTableView = UITableView()
    var rightTableView = UITableView()

    var removeIndex = IndexPath()

    var leftItems: [String] = [
        "Hello",
        "What",
        "is",
        "happening"
    ]
    var rightItems: [String] = [
        "I",
        "don't",
        "know"
    ]

    func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
        let string = tableView == leftTableView ? leftItems[indexPath.row] : rightItems[indexPath.row]
        self.removeIndex = indexPath
        guard let data = string.data(using: .utf8) else { return [] }
        let itemProvider = NSItemProvider(item: data as NSData, typeIdentifier: kUTTypePlainText as String)

        return [UIDragItem(itemProvider: itemProvider)]
    }

    func tableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator) {
        let destinationIndexPath: IndexPath

        if let indexPath = coordinator.destinationIndexPath {
            destinationIndexPath = indexPath
        } else {
            let section = tableView.numberOfSections - 1
            let row = tableView.numberOfRows(inSection: section)
            destinationIndexPath = IndexPath(row: row, section: section)
        }

        coordinator.session.loadObjects(ofClass: NSString.self) { items in
            guard let strings = items as? [String] else {
                return
            }
            var indexPaths = [IndexPath]()
            for (index, string) in strings.enumerated() {
                let indexPath = IndexPath(row: destinationIndexPath.row + index, section: destinationIndexPath.section)
                if tableView == self.leftTableView {
                    self.leftItems.insert(string, at: indexPath.row)
                } else {
                    self.rightItems.insert(string, at: indexPath.row)
                }
                indexPaths.append(indexPath)
            }
            if tableView == self.leftTableView {
                self.rightItems.remove(at: self.removeIndex.row)
                self.rightTableView.deleteRows(at: [self.removeIndex], with: .automatic)
            } else {
                self.leftItems.remove(at: self.removeIndex.row)
                self.leftTableView.deleteRows(at: [self.removeIndex], with: .automatic)
            }
            tableView.insertRows(at: indexPaths, with: .automatic)
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        leftTableView.dataSource = self
        rightTableView.dataSource = self

        leftTableView.frame = CGRect(x: 0, y: 40, width: 150, height: 400)
        rightTableView.frame = CGRect(x: 150, y: 40, width: 150, height: 400)

        leftTableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
        rightTableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")

        view.addSubview(leftTableView)
        view.addSubview(rightTableView)

        leftTableView.dragDelegate = self
        leftTableView.dropDelegate = self
        rightTableView.dragDelegate = self
        rightTableView.dropDelegate = self

        leftTableView.dragInteractionEnabled = true
        rightTableView.dragInteractionEnabled = true
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if tableView == leftTableView {
            return leftItems.count
        } else {
            return rightItems.count
        }
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)

        if tableView == leftTableView {
            cell.textLabel?.text = leftItems[indexPath.row]
        } else {
            cell.textLabel?.text = rightItems[indexPath.row]
        }

        return cell
    }
}

After that you wrap this:之后你包装这个:

struct TableView: UIViewControllerRepresentable {

    func makeUIViewController(context: Context) -> TableViewController {
        let v = TableViewController()
        return v
    }

    func updateUIViewController(_ viewController: TableViewController, context: Context) {

    }

}

and finally use it:最后使用它:

struct ContentView: View {


    var body: some View {
        VStack {
            TableView()
        }
    }
}

I hope this helps.我希望这有帮助。

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

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