是否可以使用iOS 11拖放功能在UITableView中一次重新排序多个项目/单元格?

问题描述 投票:6回答:2

我知道在使用新的UITableViewDropDelegateUITableViewDragDelegate代表时,可以对单个项目/单元格进行重新排序,但是是否可以支持处理多个项目/单元格。

例如,在此屏幕截图中,我持有一个项目:Dragging a single item/cell

放下牢房就把它放进去了。

然而,当我抓住多个单元格时,我得到了无条目符号,并且单元格不会重新排序:Multiple selection Drag and Drop with no entry sign

如果我是来自另一个应用程序的多个项目,它可以正常工作,例如从iMessage中拖出多个消息:Multiple selection Drag and Drop from iMessage

是否可以在仅使用本地项目重新排序表格视图时执行此操作,以便您可以更快地重新排序?

这是我的代码:

UITableViewDragDelegate

extension DotViewController: UITableViewDragDelegate {
    func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
        return [getDragItem(forIndexPath: indexPath)]
    }

    func tableView(_ tableView: UITableView, itemsForAddingTo session: UIDragSession, at indexPath: IndexPath, point: CGPoint) -> [UIDragItem] {
        return [getDragItem(forIndexPath: indexPath)]
    }

    func getDragItem(forIndexPath indexPath: IndexPath) -> UIDragItem {
        // gets the item
    }
}

UITableViewDropDelegate

extension DotViewController: UITableViewDropDelegate {
    func tableView(_ tableView: UITableView, canHandle session: UIDropSession) -> Bool {
        return true
    }

    func tableView(_ tableView: UITableView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UITableViewDropProposal {
        return UITableViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
    }

    func tableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator) {
        // Handles Drop
    }
}

viewDidLoad

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.dataSource = self
    tableView.delegate = self
    tableView.dragDelegate = self
    tableView.dropDelegate = self

    tableView.dragInteractionEnabled = true
}
ios swift uitableview drag-and-drop ios11
2个回答
1
投票

可以通过拖动委托(例如section.row的数组)提供对所有选定单元格的引用,然后实现tableView:performDropWith:withCoordinator来重新排序它们,从而自己进行多行重新排序。 (我怀疑你知道这个)

如果你想通过返回UITableViewDropProposal的drop提议(操作:.move,intent:.insertAtDestinationIndexPath)来支持重新排序,那么UIKit使用iOS 11之前的tableView:moveRowAt:来运行,那么这只支持一行。

表视图moveRowAt IndexPath到IndexPath。如果您愿意,可以使用拖放功能继续实现此操作以支持重新排序。因为表视图实际上是调用它而不是通过使用协调器执行drop调用,如果你已经返回了魔法删除提议并且实际上正在重新排序单行。

资料来源:https://developer.apple.com/videos/play/wwdc2017/223/?time=1836


0
投票

我恐怕我不能在这里详细介绍,但基本上我是如何让它工作的:

  1. 我扩展了一个我在StackOverflow上找到的算法来获得一个可以用来重新排序我的数据源的工作函数。这是我可能的超低效/不准确的代码:

数组中的多元素重新排序(示例用于int,但可以修改为使用索引路径和数据源类型:

// Multiple element reordering in array
func reorderList(list: Array<Int>, draggedIndices: Array<Int>, targetIndex: Int) -> Array<Int> {

    // Defining the offsets that occur in destination and source indexes when we iterate over them one by one
    var array = list
    var draggedItemOffset = 0
    var targetIndexOffset = 0

    // Items being dragged ordered by their indexPaths
    let orderedDragIndices = draggedIndices.sorted() // Add {$0.row < $1.row for sorting IndexPaths}

    // Items being dragged ordered by their selection order
    var selectionOrderDragItems = [Int]()

    draggedIndices.forEach { (index) in
        selectionOrderDragItems.append(array[index])
    }

    // Reordering the list
    for i in (0...(orderedDragIndices.count - 1)).reversed()  {
        let removedItem = array.remove(at: orderedDragIndices[i] + draggedItemOffset)

        array.insert(removedItem, at: targetIndex + targetIndexOffset)

        if (i - 1 >= 0) && orderedDragIndices[i - 1] >= targetIndex {
            draggedItemOffset += 1
        } else {
            draggedItemOffset = 0
            targetIndexOffset -= 1
        }
    }

    // Right now the dropped items are in the order of their source indexPaths. Returning them back to the order of selection
    for index in Array(targetIndex + targetIndexOffset + 1...targetIndexOffset).sorted(by: >) {
        array.remove(at: index)
    }
    array.insert(contentsOf: selectionOrderDragItems, at: targetIndex + targetIndexOffset + 1)

    return array
}
  1. 在dragDelegate和dropDelegate方法中,我使用单项重新排序(UITableViewDropProposal(操作:.move,intent:.insertAtDestinationIndexPath))来获取自由动画,其他单元格为放置创建空间。但是,当用户点击其他行时,我在拖动会话处于活动状态时使用didSelectRow收集了这些额外的indexPath。
  2. 使用上面选定行的数组,在performDrop委托方法中,我使用(1)中描述的算法重构我的数据源并使用动画重新加载tableview部分。
  3. 我做了一些额外的动画,向用户显示使用panGestureRecognizer在手指下收集行,并在选择时创建单元格的快照。
  4. 请注意,我在此过程中没有使用canMoveRowAt或canEditRowAt或moveRowAt或其他传统方法。我使用了iOS 11 API中的performDrop方法。

希望它有所帮助,并且如果您发现算法存在某些失败的情况,请回复。谢谢,祝你好运!

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.