前言
最近参与了事务流程工具化组件的开发,其中有一个模块需要通过长按移动Table View Cells
,来达到调整任务的需求,在此记录下开发过程中的实现思路。完成后的效果如下图所示:
实现思路
- 添加手势
首先给collection view
添加一个UILongGestureRecognizer
,在项目中一般使用懒加载的方式来对对象进行初始化:
- (UICollectionView *)collectionView {
if (!_collectionView) {
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:self.flowLayout];
_collectionView.backgroundColor = [UIColor whiteColor];
_collectionView.dataSource = self;
_collectionView.delegate = self;
[_collectionView registerClass:[TLCMainCollectionViewCell class] forCellWithReuseIdentifier:[TLCMainCollectionViewCell identifier]];
_collectionView.showsHorizontalScrollIndicator = NO;
_collectionView.showsVerticalScrollIndicator = NO;
_collectionView.bounces = YES;
_collectionView.decelerationRate = 0;
[_collectionView addGestureRecognizer:self.longPress];
}
return _collectionView;
}
- (UILongPressGestureRecognizer *)longPress {
if (!_longPress) {
_longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressGestureRecognized:)];
}
return _longPress;
}
在用户长按后,触犯长按事件,先获取到当前手势所在的collection view
位置,再做后续的处理。
- (void)longPressGestureRecognized:(UILongPressGestureRecognizer *)sender {
CGPoint location = [sender locationInView:sender.view];
UIGestureRecognizerState state = sender.state;
switch (state) {
case UIGestureRecognizerStateBegan: {
[self handleLongPressStateBeganWithLocation:location];
}
break;
case UIGestureRecognizerStateChanged: {
}
break;
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled: {
[self longGestureEndedOrCancelledWithLocation:location];
}
break;
default:
break;
}
}
- 长按手势状态为开始
主要处理两个方面的事务,一为获取当前长按手势所对应的Table View Cell
的镜像,将其添加到Collection View
上。二为一些初始状态的设置,后续在移动后网络请求出错及判断当前手势所处的Table View
和上一次是否一致需要使用到。最后调用startPageEdgeScroll
开启定时器。
- (void)handleLongPressStateBeganWithLocation:(CGPoint)location {
TLCMainCollectionViewCell *selectedCollectionViewCell = [self currentTouchedCollectionCellWithLocation:location];
NSIndexPath *touchIndexPath = [self longGestureBeganIndexPathForRowAtPoint:location atTableView:selectedCollectionViewCell.tableView];
if (!selectedCollectionViewCell || !touchIndexPath) {
return ;
}
self.selectedCollectionViewCellRow = [self.collectionView indexPathForCell:selectedCollectionViewCell].row;
// 已完成的任务,不支持排序
TLPlanItem *selectedItem = [self.viewModel itemAtIndex:self.selectedCollectionViewCellRow
subItemIndex:touchIndexPath.section];
if (!selectedItem || selectedItem.finish) {
return;
}
selectedItem.isHidden = YES;
self.snapshotView = [self snapshotViewWithTableView:selectedCollectionViewCell.tableView
atIndexPath:touchIndexPath];
[self.collectionView addSubview:self.snapshotView];
self.selectedIndexPath = touchIndexPath;
self.originalSelectedIndexPathSection = touchIndexPath.section;
self.originalCollectionViewCellRow = self.selectedCollectionViewCellRow;
self.previousPoint = CGPointZero;
[self startPageEdgeScroll];
}
- 长按手势状态为改变
在longPressGestureRecognized
方法中,可以发现,长按手势状态改变时,并未做任何的操作,主要原因是如果在此做Table View Cells
的移动操作,如果数据超过一屏幕,无法自动将未在屏幕上的数据滚动显示出来。所以在长按手势状态为开始时,如果触摸点在Table View Cell
上,开启定时器,来处理长按手势状态为改变时的情况。
- (void)startPageEdgeScroll {
self.edgeScrollTimer = [CADisplayLink displayLinkWithTarget: