Reputation: 2491
I am dragging and dropping a table view cell. But it shows a plus icon when on top of a cell and if I drop, the text gets appended. How to prevent this plus icon and append behaviour and just allow to reorder?
extension CheckListTableViewController: UITableViewDragDelegate {
func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
if let item = self.boardMan.getCheckListItem(indexPath: indexPath) {
if let stringData = item.title.data(using: .utf8) {
let itemProvider = NSItemProvider(item: stringData as NSData, typeIdentifier: kUTTypePlainText as String)
let dragItem = UIDragItem(itemProvider: itemProvider)
dragItem.localObject = (item, indexPath, tableView)
return [dragItem]
}
}
return []
}
extension CheckListTableViewController: UITableViewDropDelegate {
func tableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator) {
if coordinator.session.hasItemsConforming(toTypeIdentifiers: [kUTTypePlainText as String]) {
coordinator.session.loadObjects(ofClass: NSString.self) { (items) in
switch (coordinator.items.first?.sourceIndexPath, coordinator.destinationIndexPath) {
case (.some(let sourceIndexPath), .some(let destinationIndexPath)):
Log.debug("src: \(sourceIndexPath) dest: \(destinationIndexPath)")
let updatedIndexPaths: [IndexPath]
if sourceIndexPath.row < destinationIndexPath.row {
updatedIndexPaths = (sourceIndexPath.row...destinationIndexPath.row).map { IndexPath(row: $0, section: 0) }
} else if sourceIndexPath.row > destinationIndexPath.row {
updatedIndexPaths = (destinationIndexPath.row...sourceIndexPath.row).map { IndexPath(row: $0, section: 0) }
} else {
updatedIndexPaths = []
}
if let checkListItem = self.utils.getCheckListItem(indexPath: sourceIndexPath) {
self.tableView.beginUpdates()
_ = self.utils.removeCheckListItem(indexPath: sourceIndexPath)
_ = self.utils.insertCheckListItem(checkListItem, indexPath: destinationIndexPath)
self.tableView.reloadRows(at: updatedIndexPaths, with: .none)
self.tableView.endUpdates()
}
default:
Log.debug("default case")
}
}
}
}
func tableView(_ tableView: UITableView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UITableViewDropProposal {
if tableView.hasActiveDrag {
return UITableViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
}
return UITableViewDropProposal(operation: .forbidden)
}
}
The table view has drag drop delegates set and has swipe guestures added.
self.tableView.dragDelegate = self
self.tableView.dropDelegate = self
self.tableView.dragInteractionEnabled = true
Please see the screenshot below.
Upvotes: 0
Views: 935
Reputation: 318824
If you want to support drag and drop only for the purpose of reordering rows, then you don't need any of the code you posted.
Implement the normal "reorder" related methods of UITableViewDataSource and UITableViewDelegate. Set the table's dragDelegate
and dropDelegate
. You only need to implement one method each from UITableViewDragDelegate and UITableViewDropDelegate and their implementations are trivial.
For a simple one-section table view all you need is the following:
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
// Update your data model array to move the item at sourceIndexPath.row to destinationIndexPath.row
}
// MARK: - UITableViewDragDelegate
func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
return []
}
// MARK: - UITableViewDropDelegate
func tableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator) {
// no-op
}
Make sure you set the table view's dragDelegate
and dropDelegate
properties to self
in viewDidLoad
or in the storyboard. You also need to turn on the dragInteractionEnabled
property.
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.dragDelegate = self
self.tableView.dropDelegate = self
self.tableView.dragInteractionEnabled = true
}
That's all you need to support row reordering using drag and drop. Of course for complicated data models and multiple sections, you may need to also implement the targetIndexPathForMoveFromRowAt
delegate method and your logic in moveRowAt
may need further logic.
What's interesting is that the need to set the dropDelegate
and to enable the dragInteractionEnabled
is only needed for iPhones. The iPad (and Mac Catalyst) version does not need those set.
Upvotes: 2