【问题标题】:How to prevent appending data to an existing cell on drag drop of table view cell?如何防止在表格视图单元格的拖放中将数据附加到现有单元格?
【发布时间】:2019-11-07 16:22:31
【问题描述】:

我正在拖放一个表格视图单元格。但它在单元格顶部显示一个加号图标,如果我放下,文本会被附加。如何防止这个加号图标和附加行为,只允许重新排序?

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

表格视图设置了拖放代表并添加了滑动访客。

self.tableView.dragDelegate = self
self.tableView.dropDelegate = self
self.tableView.dragInteractionEnabled = true

请看下面的截图。

【问题讨论】:

    标签: ios swift uitableview drag-and-drop


    【解决方案1】:

    如果您只想支持拖放以重新排序行,那么您不需要您发布的任何代码。

    实现UITableViewDataSource和UITableViewDelegate的正常“重新排序”相关方法。设置表的dragDelegatedropDelegate。您只需要从 UITableViewDragDelegate 和 UITableViewDropDelegate 中分别实现一个方法,它们的实现很简单。

    对于一个简单的单节表格视图,您只需要以下内容:

    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
    }
    

    确保在viewDidLoad 或情节提要中将表格视图的dragDelegatedropDelegate 属性设置为self。您还需要开启dragInteractionEnabled 属性。

    override func viewDidLoad() {
        super.viewDidLoad()
    
        self.tableView.dragDelegate = self
        self.tableView.dropDelegate = self
        self.tableView.dragInteractionEnabled = true
    }
    

    这就是使用拖放支持行重新排序所需的全部内容。当然对于复杂的数据模型和多个部分,您可能还需要实现targetIndexPathForMoveFromRowAt委托方法,您在moveRowAt中的逻辑可能需要进一步的逻辑。


    有趣的是,只有 iPhone 需要设置 dropDelegate 和启用 dragInteractionEnabled。 iPad(和 Mac Catalyst)版本不需要这些设置。

    【讨论】:

    • 在这种情况下,我可以拖动,但不能放下。 moveRowAt 方法未被调用。
    • 它在我用于此答案的简单测试应用程序中为我工作。您正在测试哪个版本的 Xcode 和 iOS?
    • 我正在使用Xcode Version 11.2 (11B52)iPhone 11 Pro Max 13.2模拟器。
    • 奇怪。在 iPad 模拟器上它工作正常,但在 iPhone sim 上,我的测试项目根本不允许拖放重新排序。给我几分钟。
    • 我搞定了。我将dropDelegate 设置为空实现,并且移动工作没有加号出现。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2016-09-13
    • 1970-01-01
    • 2021-06-04
    • 1970-01-01
    • 1970-01-01
    • 2011-10-05
    • 2020-08-13
    • 1970-01-01
    相关资源
    最近更新 更多