UICollectionView有效的拖放
我目前正在尝试使用UICollectionView实现UITableView重sorting行为。
我们来调用一个UItableView TV和一个UICollectionView CV (澄清下面的解释)
我基本上试图重现电视的拖放,但我没有使用编辑模式,只要长按手势被触发,电池就准备好被移动。 它工作正常,我使用CV的移动方法,一切都很好。
我更新CV的contentOffset属性以处理用户拖动单元格时的滚动。 当用户到达顶部和底部的特定矩形时,我更新contentOffset和CV滚动。 问题是当用户停止移动它的手指时,手势不发送任何更新,这使得滚动停止并且一旦用户移动他的手指就重新开始。
这种行为是绝对不自然的,我宁愿继续滚动,直到用户释放简历,因为它是在电视的情况下。 电视拖拽的经验是真棒,我真的想重现相同的感觉。 有谁知道他们如何pipe理在重新sorting电视的滚动?
- 我试着用一个定时器重复触发滚动动作,只要手势位置在正确的位置,滚动是可怕的,并不是非常有效率(非常缓慢和跳动)。
- 我也尝试使用GCD在另一个线程中聆听手势位置,但结果甚至更糟。
我没有想到这个,所以如果有人有答案,我会嫁给他!
这里是longPress方法的实现:
- (void)handleLongPress:(UILongPressGestureRecognizer *)sender { ReorganizableCVCLayout *layout = (ReorganizableCVCLayout *)self.collectionView.collectionViewLayout; CGPoint gesturePosition = [sender locationInView:self.collectionView]; NSIndexPath *selectedIndexPath = [self.collectionView indexPathForItemAtPoint:gesturePosition]; if (sender.state == UIGestureRecognizerStateBegan) { layout.selectedItem = selectedIndexPath; layout.gesturePoint = gesturePosition; // Setting gesturePoint invalidate layout } else if (sender.state == UIGestureRecognizerStateChanged) { layout.gesturePoint = gesturePosition; // Setting gesturePoint invalidate layout [self swapCellAtPoint:gesturePosition]; [self manageScrollWithReferencePoint:gesturePosition]; } else { [self.collectionView performBatchUpdates:^ { layout.selectedItem = nil; layout.gesturePoint = CGPointZero; // Setting gesturePoint invalidate layout } completion:^(BOOL completion){[self.collectionView reloadData];}]; } }
为了使CV滚动,我正在使用该方法:
- (void)manageScrollWithReferencePoint:(CGPoint)gesturePoint { ReorganizableCVCLayout *layout = (ReorganizableCVCLayout *)self.collectionView.collectionViewLayout; CGFloat topScrollLimit = self.collectionView.contentOffset.y+layout.itemSize.height/2+SCROLL_BORDER; CGFloat bottomScrollLimit = self.collectionView.contentOffset.y+self.collectionView.frame.size.height-layout.itemSize.height/2-SCROLL_BORDER; CGPoint contentOffset = self.collectionView.contentOffset; if (gesturePoint.y < topScrollLimit && gesturePoint.y - layout.itemSize.height/2 - SCROLL_BORDER > 0) contentOffset.y -= SCROLL_STEP; else if (gesturePoint.y > bottomScrollLimit && gesturePoint.y + layout.itemSize.height/2 + SCROLL_BORDER < self.collectionView.contentSize.height) contentOffset.y += SCROLL_STEP; [self.collectionView setContentOffset:contentOffset]; }
这可能有帮助
https://github.com/lxcid/LXReorderableCollectionViewFlowLayout
这扩展了UICollectionView
以允许每个UICollectionViewCells
通过长时间触摸(又名触摸并保持)由用户手动重新安排。 用户可以将单元格拖到集合中的任何其他位置,其他单元格将自动重新sorting。 谢谢你去lxcid 。
这是一个替代scheme:
DraggableCollectionView和LXReorderableCollectionViewFlowLayout之间的区别是:
- 数据源只能更改一次。 这意味着,当用户拖动一个项目时,单元格被重新定位而不修改数据源。
- 它的写法使得可以使用自定义布局。
- 它使用
CADisplayLink
进行平滑的滚动和animation。 - 拖动时animation取消的频率较低。 感觉更“自然”。
- 该协议使用类似于
UITableViewDataSource
方法来扩展UICollectionViewDataSource
。
这是一个正在进行的工作。 现在支持多个部分。
要在自定义布局中使用它,请参阅DraggableCollectionViewFlowLayout
。 大多数逻辑存在于LSCollectionViewLayoutHelper
。 CircleLayoutDemo中还有一个例子,展示了如何从WWDC 2012工作中创buildApple的CircleLayout示例。
从iOS 9开始, UICollectionView
现在支持重新sorting。
对于UICollectionViewController
,只需重写collectionView(collectionView: UICollectionView, moveItemAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath)
对于UICollectionView
,除了实现上面的UICollectionViewDataSource
方法外,还必须自己处理手势。
以下是源代码:
private var longPressGesture: UILongPressGestureRecognizer! override func viewDidLoad() { super.viewDidLoad() longPressGesture = UILongPressGestureRecognizer(target: self, action: "handleLongGesture:") self.collectionView.addGestureRecognizer(longPressGesture) } func handleLongGesture(gesture: UILongPressGestureRecognizer) { switch(gesture.state) { case UIGestureRecognizerState.Began: guard let selectedIndexPath = self.collectionView.indexPathForItemAtPoint(gesture.locationInView(self.collectionView)) else { break } collectionView.beginInteractiveMovementForItemAtIndexPath(selectedIndexPath) case UIGestureRecognizerState.Changed: collectionView.updateInteractiveMovementTargetPosition(gesture.locationInView(gesture.view!)) case UIGestureRecognizerState.Ended: collectionView.endInteractiveMovement() default: collectionView.cancelInteractiveMovement() } }
来源: https : //developer.apple.com/library/ios/documentation/UIKit/Reference/UICollectionView_class/#//apple_ref/doc/uid/TP40012177-CH1-SW67
http://nshint.io/blog/2015/07/16/uicollectionviews-now-have-easy-reordering/
如果你想实验自己,我只写了一个基于Swift的教程,你可以看看。 我试图build立最基本的情况,以便更容易遵循这一点 。
这是另一种方法:
关键的区别在于,该解决scheme不需要“鬼”或“虚拟”单元来提供拖放function。 它只是使用单元格本身。 animation符合UITableView。 它通过在移动时调整集合视图布局的私有数据源来工作。 一旦你放手,它会告诉你的控制器,你可以将改变提交给你自己的数据源。
我相信在大多数使用情况下工作要简单一些。 仍然是一个正在进行的工作,但还有另一种方法来实现这一点。 大多数人应该觉得这很容易融入自己的自定义UICollectionViewLayouts。