Swift开发:UITableView单元格左右滑动已实现,求指定区段内长按拖动方法
实现UITableView单元格长按拖动(指定区段内移动)
嘿,我来帮你搞定这个拖动移动的功能!你已经完成了左右滑动操作,接下来的拖动其实没那么复杂,而且可以轻松限制只在指定区段内移动,下面分两种方案给你讲解(分别适配不同iOS版本):
方案一:iOS 11+ 现代拖拽API(推荐)
这个方案是苹果推荐的现代交互方式,默认就是长按触发拖拽,体验更流畅,代码也简洁:
1. 设置代理
首先在你的ViewController里,给tableView设置拖拽和放置代理:
override func viewDidLoad() { super.viewDidLoad() // 其他已有的代码... tableView.dragDelegate = self tableView.dropDelegate = self }
2. 实现拖拽代理方法
返回拖动的单元格数据,这里我们把indexPath存起来方便后续处理:
extension YourViewController: UITableViewDragDelegate { func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] { // 这里用indexPath作为拖动对象,你也可以换成自己的数据模型 let itemProvider = NSItemProvider(object: indexPath as NSItemProviderWriting) let dragItem = UIDragItem(itemProvider: itemProvider) dragItem.localObject = indexPath // 保存源indexPath return [dragItem] } }
3. 实现放置代理方法(核心:限制区段)
这里重点处理只允许在同一个区段内移动的逻辑:
extension YourViewController: UITableViewDropDelegate { // 确认是否可以处理当前拖动会话 func tableView(_ tableView: UITableView, canHandle session: UIDropSession) -> Bool { return session.canLoadObjects(ofClass: IndexPath.self) } // 配置放置行为:只有源和目标在同一区段时才允许移动 func tableView(_ tableView: UITableView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UITableViewDropProposal { guard let sourceIndexPath = session.items.first?.localObject as? IndexPath, let destIndexPath = destinationIndexPath, sourceIndexPath.section == destIndexPath.section else { // 不在同一区段,取消操作 return UITableViewDropProposal(operation: .cancel) } // 允许移动 return UITableViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath) } // 执行放置操作:更新数据源和UI func tableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator) { guard let destinationIndexPath = coordinator.destinationIndexPath, let sourceIndexPath = coordinator.items.first?.dragItem.localObject as? IndexPath, sourceIndexPath.section == destinationIndexPath.section else { return } // 1. 更新你的数据源(这里替换成你自己的数据源数组) let movedItem = yourDataSource[sourceIndexPath.section][sourceIndexPath.row] yourDataSource[sourceIndexPath.section].remove(at: sourceIndexPath.row) yourDataSource[destinationIndexPath.section].insert(movedItem, at: destinationIndexPath.row) // 2. 更新tableView的UI tableView.performBatchUpdates({ tableView.moveRow(at: sourceIndexPath, to: destinationIndexPath) }, completion: nil) // 完成拖拽动画 coordinator.drop(coordinator.items.first!.dragItem, toRowAt: destinationIndexPath) } }
方案二:兼容iOS 10及以下的传统编辑模式
如果你需要适配更早的iOS版本,可以用编辑模式+长按手势的方式:
1. 添加长按手势
在viewDidLoad里给tableView添加长按手势,触发编辑模式:
override func viewDidLoad() { super.viewDidLoad() // 其他已有的代码... let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(_:))) tableView.addGestureRecognizer(longPressGesture) }
2. 处理长按手势
@objc private func handleLongPress(_ gesture: UILongPressGestureRecognizer) { switch gesture.state { case .began: let touchPoint = gesture.location(in: tableView) if let indexPath = tableView.indexPathForRow(at: touchPoint) { // 可选:只允许特定区段的单元格触发拖动 if indexPath.section == yourTargetSection { // 替换成你允许的区段,比如0 tableView.setEditing(true, animated: true) } } case .ended: tableView.setEditing(false, animated: true) default: break } }
3. 实现数据源方法(限制拖动和移动范围)
extension YourViewController { // 允许指定区段的单元格被拖动 func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { return indexPath.section == yourTargetSection // 替换成你的目标区段 } // 限制只能在同一区段内移动 func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { guard sourceIndexPath.section == destinationIndexPath.section else { return } // 更新数据源(替换成你自己的数据源) let movedItem = yourDataSource[sourceIndexPath.section][sourceIndexPath.row] yourDataSource[sourceIndexPath.section].remove(at: sourceIndexPath.row) yourDataSource[destinationIndexPath.section].insert(movedItem, at: destinationIndexPath.row) } }
注意事项
- 这两种方案都可以和你已有的左右滑动操作共存,因为滑动是
leadingSwipeActionsConfigurationForRowAt和trailingSwipeActionsConfigurationForRowAt方法实现的,和拖动逻辑完全独立。 - 记得替换代码中的
yourDataSource和yourTargetSection为你实际的数据源数组和目标区段编号。
这样就能实现长按单元格后在指定区段内拖动移动的功能啦!如果有细节需要调整,随时说~
内容的提问来源于stack exchange,提问作者iosdev
相关产品推荐
相关产品推荐

