问题 使用长按手势重新排序tableview中的单元格?


我希望能够使用longPress手势(不使用标准重新排序控件)重新排序tableview单元格。在识别出longPress之后,我希望tableView基本上进入“编辑模式”,然后重新排序,好像我正在使用Apple提供的重新排序控件一样。

有没有办法在不需要依赖第三方解决方案的情况下做到这一点?

提前致谢。

编辑:我最终使用了接受的答案中的解决方案,并依赖于第三方解决方案。


13009
2017-09-04 04:55


起源

嘿我试图做同样的事情。你最终用的是什么? - snapfish


答案:


所以基本上你想要的 行“重新排序”中的“清除”行 对? (约0:15)

这篇SO帖子可能有所帮助。 

不幸的是,我不认为你可以用现在的iOS SDK工具做到这一点,而不是从头开始一起攻击UITableView + Controller(你需要自己创建每一行并让UITouch响应与你行的CGRect相关) -移动)。

它会非常复杂,因为当您移动要重新排序的行时,您需要获取行的“动画”。

cocoas工具看起来很有希望,至少可以看一下来源。


3
2017-09-05 21:39



是的,这正是我想要的重新排序的类型,谢谢。我希望避免第三方解决方案或从头开始“黑客攻击”事情,但在这种情况下可能是不可避免的。 - Michael Campsall


你不能用iOS SDK工具做到这一点,除非你想从头开始把你自己的UITableView + Controller放在一起,这需要大量的工作。您提到不依赖第三方解决方案,但我的自定义UITableView类可以很好地处理这个问题。随意查看:

https://github.com/bvogelzang/BVReorderTableView


8
2018-03-12 19:22



做得好!谢谢! - ZviBar


Swift 3并没有第三方解决方案

首先,将这两个变量添加到您的类中:

var dragInitialIndexPath: IndexPath?
var dragCellSnapshot: UIView?

然后加 UILongPressGestureRecognizer 到你的 tableView

let longPress = UILongPressGestureRecognizer(target: self, action: #selector(onLongPressGesture(sender:)))
longPress.minimumPressDuration = 0.2 // optional
tableView.addGestureRecognizer(longPress)

处理 UILongPressGestureRecognizer

// MARK: cell reorder / long press

func onLongPressGesture(sender: UILongPressGestureRecognizer) {
  let locationInView = sender.location(in: tableView)
  let indexPath = tableView.indexPathForRow(at: locationInView)

  if sender.state == .began {
    if indexPath != nil {
      dragInitialIndexPath = indexPath
      let cell = tableView.cellForRow(at: indexPath!)
      dragCellSnapshot = snapshotOfCell(inputView: cell!)
      var center = cell?.center
      dragCellSnapshot?.center = center!
      dragCellSnapshot?.alpha = 0.0
      tableView.addSubview(dragCellSnapshot!)

      UIView.animate(withDuration: 0.25, animations: { () -> Void in
        center?.y = locationInView.y
        self.dragCellSnapshot?.center = center!
        self.dragCellSnapshot?.transform = (self.dragCellSnapshot?.transform.scaledBy(x: 1.05, y: 1.05))!
        self.dragCellSnapshot?.alpha = 0.99
        cell?.alpha = 0.0
      }, completion: { (finished) -> Void in
        if finished {
          cell?.isHidden = true
        }
      })
    }
  } else if sender.state == .changed && dragInitialIndexPath != nil {
    var center = dragCellSnapshot?.center
    center?.y = locationInView.y
    dragCellSnapshot?.center = center!

    // to lock dragging to same section add: "&& indexPath?.section == dragInitialIndexPath?.section" to the if below
    if indexPath != nil && indexPath != dragInitialIndexPath {
      // update your data model
      let dataToMove = data[dragInitialIndexPath!.row]
      data.remove(at: dragInitialIndexPath!.row)
      data.insert(dataToMove, at: indexPath!.row)

      tableView.moveRow(at: dragInitialIndexPath!, to: indexPath!)
      dragInitialIndexPath = indexPath
    }
  } else if sender.state == .ended && dragInitialIndexPath != nil {
    let cell = tableView.cellForRow(at: dragInitialIndexPath!)
    cell?.isHidden = false
    cell?.alpha = 0.0
    UIView.animate(withDuration: 0.25, animations: { () -> Void in
      self.dragCellSnapshot?.center = (cell?.center)!
      self.dragCellSnapshot?.transform = CGAffineTransform.identity
      self.dragCellSnapshot?.alpha = 0.0
      cell?.alpha = 1.0
    }, completion: { (finished) -> Void in
      if finished {
        self.dragInitialIndexPath = nil
        self.dragCellSnapshot?.removeFromSuperview()
        self.dragCellSnapshot = nil
      }
    })
  }
}

func snapshotOfCell(inputView: UIView) -> UIView {
  UIGraphicsBeginImageContextWithOptions(inputView.bounds.size, false, 0.0)
  inputView.layer.render(in: UIGraphicsGetCurrentContext()!)
  let image = UIGraphicsGetImageFromCurrentImageContext()
  UIGraphicsEndImageContext()

  let cellSnapshot = UIImageView(image: image)
  cellSnapshot.layer.masksToBounds = false
  cellSnapshot.layer.cornerRadius = 0.0
  cellSnapshot.layer.shadowOffset = CGSize(width: -5.0, height: 0.0)
  cellSnapshot.layer.shadowRadius = 5.0
  cellSnapshot.layer.shadowOpacity = 0.4
  return cellSnapshot
}

7
2017-07-12 17:26



当我尝试将此代码与错误一起使用时,应用程序崩溃:第0部分中的行数无效。更新后现有部分中包含的行数必须等于更新前该部分中包含的行数 - Vishal Sonawane
我用数据源上的exchangeObject方法解决了这个崩溃,比如dataSource.exchangeObject(at:dragInitialIndexPath!.row,withObjectAt:indexPath!.row) - Vishal Sonawane


当然有办法。在手势识别器代码中调用方法setEditing:animated:,将表视图置于编辑模式。在Apple文档中查找“管理行的重新排序”以获取有关移动行的更多信息。


-2
2017-09-04 05:14



是的,这将有效,但我希望它是一个行动,而不是两个。我想跳过重新排序控件的需要,并且用户需要使用它们来重新排序单元格。它应该是这样的:LongPress启动编辑模式并允许用户拖动单元格而无需抬起手指并按下重新排序控件。 - Michael Campsall
jemicha,你能找到解决方案吗?我期待完成同样的任务。 - kyleplattner
我正在寻找相同的(进入编辑模式,并在一个长按开始重新排序),任何线索你如何做到这一点?请 - Nicolas Manzini
我最终使用了接受的答案解决方案 - Michael Campsall