【发布时间】: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