美文网首页
UICollectionView的item的长按移动

UICollectionView的item的长按移动

作者: 羊驼先生丶 | 来源:发表于2016-10-21 17:01 被阅读430次

    点击每一个item后移动item改变item的位置。
    实现这个功能有两种方案
    1.第一种使用苹果给出的API直接调方法(IOS9以后)
    2.第二种就是自己苦b的写移动前后的逻辑
    通过查资料获得的两个方法代码大致如下

    第一种直接调API

    增加长按手势

    //此处给其增加长按手势,用此手势触发cell移动效果
        UILongPressGestureRecognizer *longGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlelongGesture:)];
        [_itemCollectionVIew addGestureRecognizer:longGesture];
    

    手势调用的方法

    //ios9以后的系统(ios9API)
    -(void)IOS9_action:(UILongPressGestureRecognizer *)longGesture{
        //判断手势状态
        switch (longGesture.state) {
            case UIGestureRecognizerStateBegan:{
    //增加的抖动的动画
                [self shake];
                //判断手势落点位置是否在路径上
                NSIndexPath *indexPath = [self.itemCollectionVIew indexPathForItemAtPoint:[longGesture locationInView:self.itemCollectionVIew]];
                if (indexPath == nil) {
                    break;
                }
                //在路径上则开始移动该路径上的cell
                [self.itemCollectionVIew beginInteractiveMovementForItemAtIndexPath:indexPath];
            }
                break;
            case UIGestureRecognizerStateChanged:
                //移动过程当中随时更新cell位置
                [self.itemCollectionVIew updateInteractiveMovementTargetPosition:[longGesture locationInView:self.itemCollectionVIew]];
                break;
            case UIGestureRecognizerStateEnded:
                //移动结束后关闭cell移动
                [self.itemCollectionVIew endInteractiveMovement];
                break;
            default:
                [self.itemCollectionVIew cancelInteractiveMovement];
                break;
        }
    }
    
    

    系统的回调方法

    //是否允许移动item(ios9API)
    - (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath{
        //返回YES允许其item移动
        return YES;
    }
    //item移动后改变的item的回调(ios9API)
    - (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath {
    //此处可以设置移动后的数据源的数组中的位置
    //也可以不写,只是刷新后cell的状态不是你所想要的
    }
    

    调换数据源数组中的位置,可以参考下面方法
    //self.dataArray是数据源数组
    //SelectedListModel是cell的model
    //将数据源数组按照改变的item的位置重新组装数组

    -(void)compareMoveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath{
        NSInteger location = 0;
        NSInteger length = 0;
        if (sourceIndexPath.item > destinationIndexPath.item) {
            location = destinationIndexPath.item;
        }else{
            location = sourceIndexPath.item;
        }
        length = ABS(destinationIndexPath.item - sourceIndexPath.item)+1;
        NSRange rang = NSMakeRange(location , length);
        NSMutableIndexSet *set = [NSMutableIndexSet indexSet];
        [set addIndexesInRange:rang];
        NSMutableArray *array = [NSMutableArray arrayWithArray:[self.dataArray subarrayWithRange:rang]];
        [self.dataArray removeObjectsAtIndexes:set];
        if (location == sourceIndexPath.item) {
            SelectedListModel *model1 = array.firstObject;
            [array removeObjectAtIndex:0];
            [array addObject:model1];
            
        }else{
            SelectedListModel *model1 = array.lastObject;
            [array removeLastObject];
            [array insertObject:model1 atIndex:0];
        }
        [self.dataArray insertObjects:array atIndexes:set];
    }
    

    第二种是为了适配iOS9以前的系统

    用到的属性

    /**之前选中cell的NSIndexPath*/
    @property (nonatomic, strong) NSIndexPath *oldIndexPath;
    /**单元格的截图*/
    @property (nonatomic, strong) UIView *snapshotView;
    /**之前选中cell的NSIndexPath*/
    @property (nonatomic, strong) NSIndexPath *moveIndexPath;
    

    手势实现的方法

    //ios9以前的系统
    -(void)action:(UILongPressGestureRecognizer *)longPress{
        switch (longPress.state) {
            case UIGestureRecognizerStateBegan:
            { // 手势开始
                //判断手势落点位置是否在row上
                NSIndexPath *indexPath = [self.itemCollectionVIew indexPathForItemAtPoint:[longPress locationInView:self.itemCollectionVIew]];
                self.oldIndexPath = indexPath;
                if (indexPath == nil) {
                    break;
                }
                UICollectionViewCell *cell = [self.itemCollectionVIew cellForItemAtIndexPath:indexPath];
                // 使用系统的截图功能,得到cell的截图视图
                UIView *snapshotView = [cell snapshotViewAfterScreenUpdates:NO];
                snapshotView.layer.cornerRadius = 3;
                snapshotView.layer.masksToBounds = YES;
                snapshotView.frame = cell.frame;
                [self.itemCollectionVIew addSubview:self.snapshotView = snapshotView];
                // 截图后隐藏当前cell
                cell.hidden = YES;
                
                CGPoint currentPoint = [longPress locationInView:self.itemCollectionVIew];
                [UIView animateWithDuration:0.25 animations:^{
                    snapshotView.transform = CGAffineTransformMakeScale(1.05, 1.05);
                    snapshotView.center = currentPoint;
                }];
            }
                break;
            case UIGestureRecognizerStateChanged:
            { // 手势改变
                //当前手指位置 截图视图位置随着手指移动而移动
                CGPoint currentPoint = [longPress locationInView:self.itemCollectionVIew];
                self.snapshotView.center = currentPoint;
                // 计算截图视图和哪个可见cell相交
                for (UICollectionViewCell *cell in self.itemCollectionVIew.visibleCells) {
                    // 当前隐藏的cell就不需要交换了,直接continue
                    if ([self.itemCollectionVIew indexPathForCell:cell] == self.oldIndexPath) {
                        continue;
                    }
                    // 计算中心距
                    CGFloat space = sqrtf(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.itemCollectionVIew indexPathForCell:cell];
                        //移动 会调用willMoveToIndexPath方法更新数据源
                        [self.itemCollectionVIew moveItemAtIndexPath:self.oldIndexPath toIndexPath:self.moveIndexPath];
    //上面提到的方法,将数据源数组按照改变的item的位置重新组装数组
                        [self compareMoveItemAtIndexPath:_oldIndexPath toIndexPath:_moveIndexPath];
                        //设置移动后的起始indexPath
                        self.oldIndexPath = self.moveIndexPath;
                        break;
                    }
                }
            }
                break;
            default:
            { // 手势结束和其他状态
                UICollectionViewCell *cell = [self.itemCollectionVIew cellForItemAtIndexPath:self.oldIndexPath];
                // 结束动画过程中停止交互,防止出问题
                self.itemCollectionVIew.userInteractionEnabled = NO;
                // 给截图视图一个动画移动到隐藏cell的新位置
                [UIView animateWithDuration:0.25 animations:^{
                    self.snapshotView.center = cell.center;
                    self.snapshotView.transform = CGAffineTransformMakeScale(1.0, 1.0);
                } completion:^(BOOL finished) {
                    // 移除截图视图,显示隐藏的cell并开始交互
                    [self.snapshotView removeFromSuperview];
                    cell.hidden = NO;
                    self.itemCollectionVIew.userInteractionEnabled = YES;
                }];
            }
                break;
        }
    }
    
    

    根据需要调用

    - (void)handlelongGesture:(UILongPressGestureRecognizer *)longGesture {
        //判断是否是ios以前的系统
        if ([[[UIDevice currentDevice] systemVersion] floatValue] < 9.0){
            [self action:longGesture];
        }else{
           [self IOS9_action:longGesture];
        }
    }
    
    

    注释写的很清楚,理解应该不是很难。。。

    相关文章

      网友评论

          本文标题:UICollectionView的item的长按移动

          本文链接:https://www.haomeiwen.com/subject/bulcuttx.html