前言
最近項(xiàng)目中需要拖動(dòng)UITableViewCell進(jìn)行排序,基于系統(tǒng)的方法只能進(jìn)入編輯模式觸發(fā),且沒(méi)有Section間的控制方法,UI也有局限性,所以參考網(wǎng)上做法實(shí)現(xiàn)如下效果:

image.png
以實(shí)現(xiàn)不同的Section間單獨(dú)處理。
首先
在cell的操作圖片上添加長(zhǎng)按手勢(shì),根據(jù)state的值進(jìn)行操作
- (void)dragCell:(UITableViewCell *)cell recognizer:(UILongPressGestureRecognizer *)longPress {
UIGestureRecognizerState state = longPress.state;
switch (state) {
case UIGestureRecognizerStateBegan: {
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
if (indexPath) {
self.sourceIndexPath = indexPath;
self.snapshot = [self customSnapshoFromView:cell];
__block CGPoint center = cell.center;
self.snapshot.center = center;
self.snapshot.alpha = 0.0;
[self.tableView addSubview:self.snapshot];
[UIView animateWithDuration:0.25 animations:^{
self.snapshot.center = center;
self.snapshot.transform = CGAffineTransformMakeScale(1.05, 1.05);
self.snapshot.alpha = 0.98;
cell.alpha = 0.0f;
} completion:^(BOOL finished) {
cell.hidden = YES;
}];
}
break;
}
case UIGestureRecognizerStateChanged: {
CGPoint location = [longPress locationOfTouch:0 inView:self.tableView];
CGPoint center = self.snapshot.center;
center.y = location.y;
self.snapshot.center = center;
NSIndexPath *changedIndexPath = [self.tableView indexPathForRowAtPoint:location];
// 是否位置變動(dòng)
if (changedIndexPath && ![changedIndexPath isEqual:self.sourceIndexPath]) {
if (changedIndexPath.section != self.sourceIndexPath.section) {
return;
}
// 要拖動(dòng)的數(shù)據(jù)
NSArray *sectionArry = self.getAdapterArry[self.sourceIndexPath.section];
// 移動(dòng)數(shù)據(jù)交換
NSMutableArray *sourceSectionArry = sectionArry.mutableCopy;
[sourceSectionArry exchangeObjectAtIndex:changedIndexPath.row withObjectAtIndex:self.sourceIndexPath.row];
// 更新數(shù)據(jù)源
[self.getAdapterArry replaceObjectAtIndex:self.sourceIndexPath.section withObject:sourceSectionArry];
[[YSCommonDataManager shareManager] addtoKLineIndexStyleSet:self.getAdapterArry];
[self.tableView moveRowAtIndexPath:self.sourceIndexPath toIndexPath:changedIndexPath];
self.sourceIndexPath = changedIndexPath;
}
break;
}
// 最后就是默認(rèn)(拖動(dòng)完成或者未拖動(dòng))
default: {
// Clean up.
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:self.sourceIndexPath];
[UIView animateWithDuration:0.25 animations:^{
self.snapshot.center = cell.center;
self.snapshot.transform = CGAffineTransformIdentity;
self.snapshot.alpha = 0.0;
cell.alpha = 1.0f;
} completion:^(BOOL finished) {
cell.hidden = NO;
[self.snapshot removeFromSuperview];
self.snapshot = nil;
}];
self.sourceIndexPath = nil;
break;
}
}
}
接著
為了能實(shí)現(xiàn)懸浮的效果,需要?jiǎng)?chuàng)建一個(gè)快照視圖。
@property (nonatomic, strong) UIView *snapshot;
- (UIView *)customSnapshoFromView:(UIView *)inputView {
UIView *snapshot = nil;
snapshot = [inputView snapshotViewAfterScreenUpdates:YES];
snapshot.layer.masksToBounds = NO;
snapshot.layer.cornerRadius = 0.0;
snapshot.layer.shadowOffset = CGSizeMake(-5.0, 0.0);
snapshot.layer.shadowRadius = 5.0;
snapshot.layer.shadowOpacity = 0.4;
return snapshot;
}
- 在
UIGestureRecognizerStateBegan時(shí),獲取被移動(dòng)cell的起始位置sourceIndexPath,將snapshot快照視圖加入到tableView上,隱藏原來(lái)的cell。 - 在
UIGestureRecognizerStateChanged時(shí),獲取到按壓手勢(shì)的偏移位置,調(diào)整snapshot的位置,得到快照被拖移到的新位置changedIndexPath,后根據(jù)
// 是否位置變動(dòng)
if (changedIndexPath && ![changedIndexPath isEqual:self.sourceIndexPath]) { if (changedIndexPath.section != self.sourceIndexPath.section) { return; } }
來(lái)隔斷不同section間的拖動(dòng)。以及進(jìn)行數(shù)據(jù)源交換,cell交換,更新sourceIndexPath等操作。 - 最后在
default狀態(tài),根據(jù)最新的sourceIndexPath來(lái)完成拖動(dòng)完成或者失敗的動(dòng)畫(huà)效果。
至此
完成了單Section及多Section的Cell手勢(shì)拖動(dòng)。
參考文章和源碼:
iOS UITableView可以拖動(dòng)排序的Cell