UITableView 无法正确地为在屏幕外重新排序的单元格设置动画

UITableView not correctly animating cells that are re-ordered off screen

我正在为我的数据源使用 NSFetchedResultsController。

当我重新排列一个单元格并且它向上或向下移动到屏幕上或稍微离开屏幕的位置时,单元格移动到它的新位置并带有动画。

但是,当该行移动到远离屏幕的新位置时,它只是移动而没有任何动画。

理想情况下,我希望这些情况下的行向下或向上动画,直到它离开屏幕。有什么方法可以在不实现自定义方法的情况下实现这一目标吗?

我在这里使用的案例是以下委托调用中的.move:

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
    switch type {
    case .insert:
        tableView.insertRows(at: [newIndexPath!], with: UITableViewRowAnimation.none)
    case .delete:
        tableView.deleteRows(at: [indexPath!], with: UITableViewRowAnimation.none)
    case .update:
        tableView.reloadRows(at: [indexPath!], with: UITableViewRowAnimation.none)
    case .move:
        tableView.moveRow(at: indexPath!, to: newIndexPath!)
    }

}

docs 开始,UIKit 将为所有单元格设置动画移动操作,但是它发生得太快以至于不太直观。

因此,您实际上可以通过两次 move(at:,to:) 调用 performBatchUpdates 来获得所需的效果,如下所示:

guard indexPath != newIndexPath, let paths = tableView.indexPathsForVisibleRows else { return }
if paths.contains(newIndexPath!) {
    tableView.moveRow(at: indexPath!, to: newIndexPath!)
} else {
    tableView.performBatchUpdates({
        let index = indexPath < newIndexPath ? (paths.count - 1) : 2
        tableView.moveRow(at:indexPath!, to: paths[index])
        tableView.moveRow(at: paths[index], to: newIndexPath!)
    })
}

注意,要实现向上滚动动画,必须将paths索引设置为2作为向上移动的中点。