【问题标题】:UITableView drop methods never called when using tableView.reloadSections([0], with: UITableView.RowAnimation.right)使用 tableView.reloadSections([0], with: UITableView.RowAnimation.right) 时从不调用 UITableView 放置方法
【发布时间】:2019-05-05 17:59:45
【问题描述】:

我正在尝试在我的UITableView 中实现拖放。拖动部分正在工作 - 我可以将我的应用程序外部拖动到提醒应用程序中,并查看 NSItemProvider 中包含的字符串。尽管实现了 UITableViewDropDelegate 方法并在 viewDidLoad 中添加 self 作为 dropDelegate 对象,但从不调用 performDropWith 方法(无论是在模拟器中还是在真实设备上)。

我已经在我的应用程序的另一个UITableView 中成功实现了拖放。该表的位置与该表的唯一区别是在 ViewController 容器内,因此我可以实现自己的拆分视图,但据我所知,这不应该有任何区别。我已经阅读了网上关于此的所有教程,但我看不出我缺少什么。我已将我的代码精简到最低限度,但它不起作用。

我有一个指向 tableView 的 @IBOutlet,它工作正常,因为 ViewController 类中的许多其他东西都使用它。我在 Xcode 10.1 中使用 Swift 4.2。

类声明:

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

viewDidLoad 内部:

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

类内的相关拖拽方法:

func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {

    if let folder = folders?[indexPath.row] {
        Logger.log("DRAGGING FOLDER with name: \(folder.name)")

        let itemProvider = createItemProviderToDrag(with: folder.folderID)
        let dragItem = UIDragItem(itemProvider: itemProvider)

        // This stores the local object so we don't have to re-fetch it.
        dragItem.localObject = folder
        return [dragItem]
    }

    // we shouldn't ever get here; but returning an empty array means nothing should be dragged
    return []
}


private func createItemProviderToDrag(with itemID: String) -> NSItemProvider {
    let itemProvider = NSItemProvider()
    itemProvider.registerDataRepresentation(forTypeIdentifier: kUTTypePlainText as String, visibility: .all) { completion in
        let data = itemID.data(using: .utf8)
        completion(data, nil)
        return nil
    }
    return itemProvider
}

func tableView(_ tableView: UITableView, canHandle session: UIDropSession) -> Bool {
    // NOTE: This returns true
    print("Can I handle it? \(session.canLoadObjects(ofClass: NSString.self))")
    return session.canLoadObjects(ofClass: NSString.self)
}

func tableView(_ tableView: UITableView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UITableViewDropProposal {
    print("Can I drop") // NEVER PRINTS
    return UITableViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
}

func tableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator) {
    print("PERFORM DROP") // NEVER PRINTS
}

这是我在日志输出中看到的:

05-May-2019 11:11:49:049 [FolderMasterViewController.swift:204] tableView(_:itemsForBeginning:at:) -> DRAGGING FOLDER with name: folder2
Can I handle it? true
2019-05-05 11:11:50.633390-0700 CWP[34092:10212965] PBItemCollectionServicer connection disconnected.

我不相信 PBItemCollectionServicer 消息是相关的 - 我已经在另一个表的日志中看到我已经成功实现拖放的那些,其他 stackoverflow 帖子说你几乎可以忽略它们。

进一步挖掘并从一个非常空的 tableView 和静态数据源重新开始,并一点一点地添加功能 - 我发现我重新加载 tableView 的方式导致拖放功能中断。

当我更改显示的文件夹列表时,我使用的是这个:

tableView.reloadSections([0], with: UITableView.RowAnimation.right)

当我把它改成

tableView.reloadData()

突然将物品放到桌子上再次起作用,我可以看到来自tableView(_:performDropWith:) 的打印。即使将 tableView.reloadData() 放入这样的动画块中,它仍然有效:

UIView.transition(with: tableView,
                  duration: 0.5,
                  options: .transitionCrossDissolve,
                  animations: { self.tableView.reloadData() })

有谁知道为什么使用tableView.reloadSections(_:with:) 不允许拖放的一半拖放工作? (我的表只有 1 个部分)

【问题讨论】:

  • 我遇到了同样的问题。 dropSessionDidUpdate 将触发,直到调用 tableView.reloadSections()。但是,使用 reloadData() 就可以了。

标签: ios swift uitableview drag-and-drop


【解决方案1】:

根据 Apple 文档:

.move 操作仅适用于在单个应用内拖动。

func tableView(_ tableView: UITableView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UITableViewDropProposal {
    print("Can I drop") // NEVER PRINTS
    return UITableViewDropProposal(**operation: .move**, intent: .insertAtDestinationIndexPath)
}

试试.copy

【讨论】:

  • 这都在同一个应用程序中。而且 print 语句永远不会被执行,所以它永远不会走那么远。
  • 更新的问题 - UITableViewDropProposal 与问题无关。这与 reloadData 的完成方式有关。
【解决方案2】:

为了解决这个问题,我在viewDidLoad() 的最后添加了对tableView.reloadData() 的调用。这让我在更改数据并想要对其进行动画处理时继续调用tableView.reloadSections([0], with: UITableView.RowAnimation.right)

【讨论】:

    猜你喜欢
    • 2013-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多