如何在UITableViewDiffableDataSource下搭配DropCoordinator实现下落动画
在iOS 11中,苹果为UITableView引入了原生拖拽功能,为常见的拖拽交互提供了特定动画。只要你返回了正确的UIDropProposal,就能轻松实现UITableView内重排序下落的动画效果,示例代码如下:
func tableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator) { // usual code to handle drop, get dragItem, etc // .... // update the dataModel to reflect the change self?.model.updateDataSourceForDrag(from: sourceIndexPath, to: destinationIndexPath) // perform the drop animation with the drop coordinator coordinator.drop(dragItem, toRowAt: destinationIndexPath) }
这一实现可以流畅地将被拖拽的元素动画插入到UITableView中hover时对应的间隙位置。
到了iOS 13+版本,开发者开始普遍使用diffable data source,但苹果官方文档中没有任何关于dropCoordinator搭配snapshot使用的参考资料,官方指南、教程、WWDC视频都没有更新说明如何组合使用这两套API。
在拖拽操作过程中,drop controller可以正确「管理」UITableView,移动各个cell留出间隙展示拖拽cell的下落位置,但调用coordinator.drop(dragItem, toRowAt: destinationIndexPath)时不会触发实际的下落动画。
目前使用的临时解决方案是手动更新并应用snapshot:
DispatchQueue.main.async { var snapshot = self?.dataSource.snapshot() if destinationIndexPath.row > sourceIndexPath.row { snapshot?.moveItem((self?.dataSource.itemIdentifier(for: sourceIndexPath))!, afterItem: (self?.dataSource.itemIdentifier(for: destinationIndexPath))!) } else { snapshot?.moveItem((self?.dataSource.itemIdentifier(for: sourceIndexPath))!, beforeItem: (self?.dataSource.itemIdentifier(for: destinationIndexPath))!) } self?.dataSource.apply(snapshot!, animatingDifferences: false) }
该方案有一定效果,但无法和drop controller的动画打通。拖拽过程中可以看到预留下落间隙的动画,但一旦松手释放,cell会从原始indexPath的位置开始动画移动,而非从拖拽元素的当前位置开始移动,效果非常生硬。
既然dropCoordinator可以调整UITableView实现拖拽过程的动画,按理说也应该可以实现下落动画,但目前找不到对应的实现方式。
如果没有更合理的解决方案,只能将代码回滚到旧版的UITableViewDataSource方法实现。
内容的提问来源于stack exchange,提问作者flanker

