UICollecionview两个seciton之间的拖拽
2020-08-25 本文已影响0人
Sh1mmer
如果只是单个selection里的item拖拽, 对系统也没有具体的适配要求,可以直接使用iOS9之后的自带方法;
具体链接https://www.jianshu.com/p/e9eb12267109;
如果是多个section,在进行拖拽的时候就会出现一个问题:
当其中一个的section里的item全部都拖拽到另一个item之后,再往回拖的时候会发现拖不回来了;
这是因为section中cell数量为0他无法去执行 下面的方法
- (void)updateInteractiveMovementTargetPosition:(CGPoint)targetPosition API_AVAILABLE(ios(9.0));
我在这想到的有两个解决方案
一:
还是使用iOS9自带方法,但是要在每个section数据源后面再添加一个数据源,把最后一个数据源当做一个占位的cell,这样section里就不会为空了,但是感觉很不好看
具体代码:
#import "MiniProgramCell.h"
#import "HeaderView.h"
#define WIDTH self.view.frame.size.width
#define HEIGHT self.view.frame.size.height
@interface ViewController ()<UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>
@property (nonatomic) UICollectionView *miniProgramCollectionView;
@property NSMutableArray *tempArr;
@property NSMutableArray *wordArr;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor grayColor];
_tempArr = [NSMutableArray new];
for (NSInteger i = 0; i<6; i++) {
[_tempArr addObject:[NSString stringWithFormat:@"%ld",i+1]];
}
_wordArr = [NSMutableArray new];
for (int i = 65; i<75; i++) {
[_wordArr addObject:[NSString stringWithFormat:@"%c",i]];
}
[self.view addSubview:self.miniProgramCollectionView];
}
- (UICollectionView *)miniProgramCollectionView{
if (!_miniProgramCollectionView) {
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc]init];
flowLayout.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);
// flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
_miniProgramCollectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, WIDTH, HEIGHT) collectionViewLayout:flowLayout];
_miniProgramCollectionView.delegate = self;
_miniProgramCollectionView.dataSource = self;
_miniProgramCollectionView.showsVerticalScrollIndicator = NO;
//注册
[_miniProgramCollectionView registerClass:[MiniProgramCell class] forCellWithReuseIdentifier:@"reuse0"];
_miniProgramCollectionView.backgroundColor = [UIColor whiteColor];
[_miniProgramCollectionView registerClass:[HeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"headerView"];
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlelongGesture:)];
[_miniProgramCollectionView addGestureRecognizer:longPress];
}
return _miniProgramCollectionView;
}
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
return CGSizeMake((WIDTH-50)/4,(WIDTH-50)/4);
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section{
return CGSizeMake(0, 50);
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{
if (kind == UICollectionElementKindSectionHeader) {
HeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"headerView" forIndexPath:indexPath];
headerView.backgroundColor = [UIColor blueColor];
return headerView;
}else{
return nil;
}
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
if (section == 0) {
return _wordArr.count;
}
return _tempArr.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
MiniProgramCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"reuse0" forIndexPath:indexPath];
if (indexPath.section == 0) {
if ( [self.wordArr[indexPath.row] isEqualToString:@"J"]) {
cell.backgroundColor = [UIColor clearColor];
}else{
cell.backgroundColor = [UIColor redColor];
}
cell.miniProgramLabel.text = self.wordArr[indexPath.row];
}else{
if ( [self.tempArr[indexPath.row] isEqualToString:@"6"]) {
cell.backgroundColor = [UIColor clearColor];
}else{
cell.backgroundColor = [UIColor redColor];
}
cell.miniProgramLabel.text = self.tempArr[indexPath.row];
}
return cell;
}
#pragma mark 长按响应方法
- (void)handlelongGesture:(UILongPressGestureRecognizer *)longPress {
[self action:longPress];
}
- (void)action:(UILongPressGestureRecognizer *)longPress {
switch (longPress.state) {
case UIGestureRecognizerStateBegan:
{
//手势开始
//判断手势落点位置是否在row上
NSIndexPath *indexPath = [self.miniProgramCollectionView indexPathForItemAtPoint:[longPress locationInView:self.miniProgramCollectionView]];
if (indexPath == nil) {
break;
}
MiniProgramCell *cell = (MiniProgramCell *)[self.miniProgramCollectionView cellForItemAtIndexPath:indexPath];
[self.miniProgramCollectionView bringSubviewToFront:cell];
//iOS9 方法 移动cell
if (@available(iOS 9.0, *)) {
[self.miniProgramCollectionView beginInteractiveMovementForItemAtIndexPath:indexPath];
} else {
// Fallback on earlier versions
}
}
break;
case UIGestureRecognizerStateChanged:
{
//iOS9 方法 移动过程中随时更新cell位置
if (@available(iOS 9.0, *)) {
CGPoint tempPoint = [longPress locationInView:self.miniProgramCollectionView];
}
NSIndexPath *indexPath = [self.miniProgramCollectionView indexPathForItemAtPoint:tempPoint];
[self.miniProgramCollectionView updateInteractiveMovementTargetPosition:tempPoint];
} else {
// Fallback on earlier versions
}
}
break;
case UIGestureRecognizerStateEnded:
{
//手势结束
//iOS9方法 移动结束后关闭cell移动
if (@available(iOS 9.0, *)) {
[self.miniProgramCollectionView endInteractiveMovement];
NSLog(@"111111");
} else {
// Fallback on earlier versions
}
}
break;
default:
if (@available(iOS 9.0, *)) {
[self.miniProgramCollectionView cancelInteractiveMovement];
} else {
// Fallback on earlier versions
}
break;
}
}
//开启collectionView可以移动
- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 1 && indexPath.row == _tempArr.count-1) {
return NO;
}
if (indexPath.section == 0 && indexPath.row == _wordArr.count-1) {
return NO;
}
return YES;
}
//处理collectionView移动过程中的数据操作
- (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
NSString *tempStr = nil;
if (sourceIndexPath.section == 0) {
tempStr = self.wordArr[sourceIndexPath.row];
[self.wordArr removeObject:tempStr];
}else{
tempStr = self.tempArr[sourceIndexPath.row];
[self.tempArr removeObject:tempStr];
}
if (destinationIndexPath.section == 0) {
[self.wordArr insertObject:tempStr atIndex:destinationIndexPath.row];
}else{
[self.tempArr insertObject:tempStr atIndex:destinationIndexPath.row];
}
if (![[self.wordArr lastObject] isEqualToString:@"J"]||![[self.tempArr lastObject] isEqualToString:@"6"]) {
NSMutableArray *tempARR = nil;
if (![[self.wordArr lastObject] isEqualToString:@"J"]) {
tempARR = self.wordArr;
}else{
tempARR = self.tempArr;
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.miniProgramCollectionView moveItemAtIndexPath:[NSIndexPath indexPathForRow:tempARR.count-1 inSection:destinationIndexPath.section] toIndexPath:[NSIndexPath indexPathForRow:tempARR.count-2 inSection:destinationIndexPath.section]];
[tempARR exchangeObjectAtIndex:tempARR.count-2 withObjectAtIndex:tempARR.count-1];
NSLog(@"%@",tempARR);
});
}
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 2;
}
@end
二:
用iOS9之前的拖拽方案,不同的是,我们在拖拽的时候需要进行计算来判断当前的位置.来确定我们下一步将要执行的状态
代码如下:
#import "MiniProgramCell.h"
#import "HeaderView.h"
#define WIDTH self.view.frame.size.width
#define HEIGHT self.view.frame.size.height
@interface secondViewController ()<UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>
@property (nonatomic) UICollectionView *collectionView;
@property NSMutableArray *tempArr;
@property NSMutableArray *wordArr;
@property NSIndexPath *oldIndexPath;
@property NSIndexPath *moveIndexPath;
@property UIView *snapShotView;
@property BOOL isLast;
@property BOOL isScroll;
@end
@implementation secondViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor grayColor];
_tempArr = [NSMutableArray new];
for (NSInteger i = 0; i<10; i++) {
[_tempArr addObject:[NSString stringWithFormat:@"%ld",i+1]];
}
_wordArr = [NSMutableArray new];
for (int i = 65; i<77; i++) {
[_wordArr addObject:[NSString stringWithFormat:@"%c",i]];
}
[self.view addSubview:self.collectionView];
}
- (UICollectionView *)collectionView{
if (!_collectionView) {
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc]init];
flowLayout.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, WIDTH, HEIGHT) collectionViewLayout:flowLayout];
_collectionView.delegate = self;
_collectionView.dataSource = self;
_collectionView.showsVerticalScrollIndicator = NO;
//注册
[_collectionView registerClass:[MiniProgramCell class] forCellWithReuseIdentifier:@"reuse0"];
_collectionView.backgroundColor = [UIColor whiteColor];
[_collectionView registerClass:[HeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"headerView"];
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlelongGesture:)];
[_collectionView addGestureRecognizer:longPress];
}
return _collectionView;
}
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
return CGSizeMake((WIDTH-50)/4,(WIDTH-50)/4);
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section{
return CGSizeMake(0, 50);
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{
if (kind == UICollectionElementKindSectionHeader) {
HeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"headerView" forIndexPath:indexPath];
headerView.backgroundColor = [UIColor blueColor];
return headerView;
}else{
return nil;
}
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
if (section == 0) {
return _wordArr.count;
}
return _tempArr.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
MiniProgramCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"reuse0" forIndexPath:indexPath];
if (indexPath.section == 0) {
cell.miniProgramLabel.text = self.wordArr[indexPath.row];
}else{
cell.miniProgramLabel.text = self.tempArr[indexPath.row];
}
cell.backgroundColor = [UIColor redColor];
return cell;
}
#pragma mark 长按响应方法
- (void)handlelongGesture:(UILongPressGestureRecognizer *)longPress {
[self action:longPress];
}
- (void)action:(UILongPressGestureRecognizer *)longPress {
switch (longPress.state) {
case UIGestureRecognizerStateBegan:
{
NSLog(@"%f",self.collectionView.contentOffset.y);
//手势开始 判断手势落点位置是否在row上
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:[longPress locationInView:self.collectionView]];
self.oldIndexPath = indexPath;
if (indexPath == nil) {
break;
}
MiniProgramCell *cell = (MiniProgramCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
//使用系统的截图功能 得到cell的截图视图
UIView *snapshotView = [cell snapshotViewAfterScreenUpdates:NO];
[self.view addSubview:self.snapShotView = snapshotView];
snapshotView.frame = CGRectMake(cell.frame.origin.x, cell.frame.origin.y-self.collectionView.contentOffset.y, cell.frame.size.width, cell.frame.size.height);
//截图后隐藏当前cell
cell.hidden = YES;
CGPoint currentPoint = [longPress locationInView:self.view];
NSLog(@"%f,%f",currentPoint.x,currentPoint.y);
[UIView animateWithDuration:0.25 animations:^{
snapshotView.transform = CGAffineTransformMakeScale(1.05, 1.05);
snapshotView.center = currentPoint;
}];
}
break;
case UIGestureRecognizerStateChanged:
{
//手势改变 当前手指位置 截图视图位置随着手指移动而移动
if (self.oldIndexPath == nil) {
break;
}
MiniProgramCell *lastCell1 = (MiniProgramCell *)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForRow:self.wordArr.count-1 inSection:0]];
MiniProgramCell *firstCell1 = (MiniProgramCell *)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
MiniProgramCell *lastCell2 = (MiniProgramCell *)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForRow:self.tempArr.count-1 inSection:1]];
MiniProgramCell *firstCell2 = (MiniProgramCell *)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]];
CGPoint currentPoint = [longPress locationInView:self.collectionView];
// 是否正在滚动
if (self.isScroll) {
self.snapShotView.center = [longPress locationInView:self.view];
break;
}
// 向下滚动
if ((currentPoint.y+(WIDTH-50)/4)>self.collectionView.frame.size.height+self.collectionView.contentOffset.y && (currentPoint.y+(WIDTH-50)/4) < self.collectionView.contentSize.height ) {
self.isScroll = YES;
[UIView animateWithDuration:0.1 animations:^{
[self.collectionView setContentOffset:CGPointMake(0,self.collectionView.contentOffset.y+30 )];
} completion:^(BOOL finished) {
self.isScroll = NO;
[self action:longPress];
}];
}
// 向上滚动
if ((currentPoint.y-(WIDTH-50)/4)<self.collectionView.contentOffset.y && (currentPoint.y-(WIDTH-50)/4) > 0 ) {
self.isScroll = YES;
[UIView animateWithDuration:0.1 animations:^{
[self.collectionView setContentOffset:CGPointMake(0,self.collectionView.contentOffset.y-30 )];
} completion:^(BOOL finished) {
self.isScroll = NO;
[self action:longPress];
}];
}
// s1->s2 第一个section像第二个section拖拽
if (self.tempArr.count == 0) {
if (currentPoint.y > lastCell1.frame.size.height+lastCell1.frame.origin.y && lastCell1) {
self.isLast = YES;
NSString *tempStr = nil;
tempStr = self.wordArr[self.oldIndexPath.row];
[self.wordArr removeObject:tempStr];
[self.tempArr insertObject:tempStr atIndex:0];
[self.collectionView moveItemAtIndexPath:self.oldIndexPath toIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]];
self.oldIndexPath = [NSIndexPath indexPathForRow:0 inSection:1];
self.snapShotView.center = [longPress locationInView:self.view];
break;
}
}else{
if (currentPoint.y > lastCell2.frame.origin.y && currentPoint.x>lastCell2.frame.origin.x+lastCell2.frame.size.width && lastCell2) {
if (self.isLast) {
self.snapShotView.center = [longPress locationInView:self.view];
break;
}
self.moveIndexPath = [NSIndexPath indexPathForRow:self.tempArr.count inSection:1];
NSString *tempStr = nil;
if (self.oldIndexPath.section == 0) {
tempStr = self.wordArr[self.oldIndexPath.row];
[self.wordArr removeObject:tempStr];
}else{
tempStr = self.tempArr[self.oldIndexPath.row];
[self.tempArr removeObject:tempStr];
NSLog(@"%@",self.tempArr);
}
if (self.moveIndexPath.section == 0) {
[self.wordArr insertObject:tempStr atIndex:self.wordArr.count];
}else{
[self.tempArr insertObject:tempStr atIndex:self.tempArr.count];
NSLog(@"%@",self.tempArr);
}
if (self.oldIndexPath.section == 1 && self.moveIndexPath.section == 1) {
self.moveIndexPath = [NSIndexPath indexPathForRow:self.tempArr.count-1 inSection:1];
}
[self.collectionView moveItemAtIndexPath:self.oldIndexPath toIndexPath:self.moveIndexPath];
self.oldIndexPath = self.moveIndexPath;
self.snapShotView.center = [longPress locationInView:self.view];
self.isLast = YES;
break;
}
}
//s2->s1 第二个section向第一个section拖拽
if (self.wordArr.count == 0) {
if (currentPoint.y < firstCell2.frame.origin.y &&firstCell2) {
self.isLast = YES;
NSString *tempStr = nil;
// self.moveIndexPath = [NSIndexPath indexPathForRow:0 inSection:1];
tempStr = self.tempArr[self.oldIndexPath.row];
[self.tempArr removeObject:tempStr];
[self.wordArr insertObject:tempStr atIndex:0];
[self.collectionView moveItemAtIndexPath:self.oldIndexPath toIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
self.oldIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];
self.snapShotView.center = [longPress locationInView:self.view];
break;
}
}else{
if (currentPoint.x>lastCell1.frame.origin.x+lastCell1.frame.size.width && currentPoint.y > lastCell1.frame.origin.y &¤tPoint.y < lastCell1.frame.origin.y+lastCell1.frame.size.height&& lastCell1 ) {
if (self.isLast ) {
self.snapShotView.center = [longPress locationInView:self.view];
break;
}
self.moveIndexPath = [NSIndexPath indexPathForRow:self.wordArr.count inSection:0];
NSString *tempStr = nil;
if (self.oldIndexPath.section == 0) {
tempStr = self.wordArr[self.oldIndexPath.row];
[self.wordArr removeObject:tempStr];
}else{
tempStr = self.tempArr[self.oldIndexPath.row];
[self.tempArr removeObject:tempStr];
}
if (self.moveIndexPath.section == 0) {
[self.wordArr insertObject:tempStr atIndex:self.wordArr.count];
}else{
[self.tempArr insertObject:tempStr atIndex:self.tempArr.count];
}
if (self.oldIndexPath.section == 0 && self.moveIndexPath.section == 0) {
self.moveIndexPath = [NSIndexPath indexPathForRow:self.wordArr.count-1 inSection:0];
}
[self.collectionView moveItemAtIndexPath:self.oldIndexPath toIndexPath:self.moveIndexPath];
self.oldIndexPath = self.moveIndexPath;
self.snapShotView.center = [longPress locationInView:self.view];
self.isLast = YES;
break;
}else{
self.isLast = NO;
}
}
self.snapShotView.center = [longPress locationInView:self.collectionView];
//计算截图视图和哪个可见cell相交
for (MiniProgramCell *cell in self.collectionView.visibleCells) {
//当前隐藏的cell就不需要交换了 直接continue
if ([self.collectionView indexPathForCell:cell] == self.oldIndexPath) {
continue;
}
//计算中心距
CGFloat space = sqrt(pow(self.snapShotView.center.x-cell.center.x, 2) + powf(self.snapShotView.center.y - cell.center.y, 2));
//如果相交一半就移动
if (space <= self.snapShotView.bounds.size.width/2) {
self.moveIndexPath = [self.collectionView indexPathForCell:cell];
/*更新数据源 须在移动之前*/
//取出移动row 数据
NSString *tempStr = nil;
if (self.oldIndexPath.section == 0) {
tempStr = self.wordArr[self.oldIndexPath.row];
[self.wordArr removeObject:tempStr];
}else{
tempStr = self.tempArr[self.oldIndexPath.row];
[self.tempArr removeObject:tempStr];
}
if (self.moveIndexPath.section == 0) {
[self.wordArr insertObject:tempStr atIndex:self.moveIndexPath.row];
}else{
[self.tempArr insertObject:tempStr atIndex:self.moveIndexPath.row];
}
//移动 会调用MoveToIndexPath方法更新数据源
[self.collectionView moveItemAtIndexPath:self.oldIndexPath toIndexPath:self.moveIndexPath];
//设置移动后的起始indexPath
self.oldIndexPath = self.moveIndexPath;
break;
}
}
self.snapShotView.center = [longPress locationInView:self.view];
}
break;
default:
{
//手势结束和其他状态
MiniProgramCell *cell = (MiniProgramCell *)[self.collectionView cellForItemAtIndexPath:self.oldIndexPath];
//结束动画过程中停止交互,防止出问题
self.collectionView.userInteractionEnabled = NO;
//给截图视图一个动画移动到隐藏cell的新位置
[UIView animateWithDuration:0.25 animations:^{
self.snapShotView.center = cell.center;
self.snapShotView.center =CGPointMake(cell.frame.origin.x+cell.frame.size.width/2, cell.frame.origin.y-self.collectionView.contentOffset.y+cell.frame.size.height/2);
self.snapShotView.transform = CGAffineTransformMakeScale(1.0, 1.0);
} completion:^(BOOL finished) {
//移除截图视图,显示隐藏的cell并开始交互
[self.snapShotView removeFromSuperview];
cell.hidden = NO;
self.isLast = NO;
self.collectionView.userInteractionEnabled = YES;
}];
}
break;
}
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 2;
}
@end