无需重新排序控制即可重新排序UITableView

时间:2011-04-11 16:54:17

标签: ios cocoa-touch uitableview drag-and-drop

我需要用户能够通过这种方式重新排序UITableView:他触摸一个单元格预定的时间段(例如1秒),然后他可以将其拖放到其他单元格上。

我知道如何使用手势识别器实现“长触摸”检测,但是在不使用重新排序控件的情况下实现拖放功能的最佳方法是什么(用户应该从单元格中的任何位置拖动单元格,不仅来自重新订购控制)?

6 个答案:

答案 0 :(得分:6)

这是一个老问题,但这是一个经过测试并使用 iOS 8 11 的解决方案。

在你的UITableViewCell子类中试试这个:

class MyTableViewCell: UITableViewCell {
    weak var reorderControl: UIView?

    override func layoutSubviews() {
        super.layoutSubviews()

        // Make the cell's `contentView` as big as the entire cell.
        contentView.frame = bounds

        // Make the reorder control as big as the entire cell 
        // so you can drag from everywhere inside the cell.
        reorderControl?.frame = bounds
    }

    override func setEditing(_ editing: Bool, animated: Bool) {
        super.setEditing(editing, animated: false)
        if !editing || reorderControl != nil {
            return
        }

        // Find the reorder control in the cell's subviews.
        for view in subviews {
            let className = String(describing: type(of:view))
            if className == "UITableViewCellReorderControl" {

                // Remove its subviews so that they don't mess up
                // your own content's appearance.
                for subview in view.subviews {
                    subview.removeFromSuperview()
                }

                // Keep a weak reference to it for `layoutSubviews()`.
                reorderControl = view

                break
            }
        }
    }
}

它接近Senseful's first suggestion,但他引用的文章似乎不再起作用。

您所做的是使重新排序控件和单元格的内容视图在编辑时与整个单元格一样大。这样,您可以从单元格内的任何位置拖动,并且您的内容会占用整个空间,就像根本没有编辑单元格一样。

最重要的缺点是,您正在改变系统的单元视图结构并引用私有类( UITableViewCellReorderControl )。它似乎适用于所有最新的iOS版本,但您必须确保每次新的操作系统出现时它仍然有效。

答案 1 :(得分:4)

我解决了以下步骤的问题:

  1. 将手势识别器附加到UITableView。
  2. 通过“长触摸”检测哪个细胞被轻拍。此时创建所选单元格的快照,将其放到UIImageView并将其放在UITableView上。 UIImageView的坐标应该是相对于UITableView的数学选择单元格(所选单元格的快照应覆盖所选单元格)。
  3. 存储所选单元格的索引,删除所选单元格并重新加载UITableView。
  4. 禁用UITableView的滚动。现在,您需要在拖动单元格时更改快照UIImageView的框架。您可以使用touchesMoved方法。
  5. 执行此操作
  6. 创建新单元格并在用户手指离开屏幕时重新加载UITableView(您已经存储了索引)。
  7. 删除快照UIImageView。
  8. 但要做到这一点并不容易。

答案 2 :(得分:2)

供将来参考...... 我遇到了同样的问题,我发现了另一个问题(Swift - Drag And Drop TableViewCell with Long Gesture Recognizer)并且有人建议了这个教程:https://www.freshconsulting.com/create-drag-and-drop-uitableview-swift/ 对我来说非常合适

答案 3 :(得分:1)

文章Reordering a UITableViewCell from any touch point讨论了这个确切的场景。

基本上,您可以执行以下操作:

  1. 找到UITableViewCellReorderControl(私人课程)。
  2. 展开它,使其跨越整个单元格。
  3. 隐藏它。
  4. 用户现在可以从任何地方拖动单元格。

  5. 另一个解决方案Cookbook: Moving Table View Cells with a Long Press Gesture通过执行以下操作实现了相同的效果:

    1. 在表格视图中添加长按手势识别器。
    2. 拖动单元格时创建单元格的快照。
    3. 在拖动单元格时,移动快照,然后调用-[UITableView moveRowAtIndexPath:toIndexPath:]
    4. 手势结束时,隐藏单元格快照。

答案 4 :(得分:0)

我知道这是关于UITableView的问题。但最后我提出了使用UICollectionView而不是UITableView来实现longtap重排序的解决方案。简单,简单。

答案 5 :(得分:0)

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


func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { }

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


func tableView(_ tableView: UITableView, dropSessionDidUpdate session: 
    UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UITableViewDropProposal {

    if session.localDragSession != nil { 
        return UITableViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
    }
    return UITableViewDropProposal(operation: .cancel, intent: .unspecified)
}

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