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.
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. This piece of code shows how you use two UITableViews
. I hope you can improve this to achieve what you are looking for.
First create this class which does all the magic. You need to import UIKit
and MobileCoreServices
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With