iOS 9以前のcollectionViewのドラッグアンドドロップ再配置の実装

6790 ワード

最近、ラベルクラスのdemoを実装する必要があるため、ドラッグ・アンド・ドロップの再配置をサポートする必要があります.まず、collectionViewが考えられ、すぐにAPIドキュメントに類似のインタフェースが見つかりました.
- (BOOL)beginInteractiveMovementForItemAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(9_0);
- (void)updateInteractiveMovementTargetPosition:(CGPoint)targetPosition NS_AVAILABLE_IOS(9_0);
- (void)endInteractiveMovement NS_AVAILABLE_IOS(9_0);
- (void)cancelInteractiveMovement NS_AVAILABLE_IOS(9_0);

システムで提供されたこれらのインタフェースはすぐに私たちのニーズを実現することができます.コードはgitbubアドレスを参照してください.しかし、上記の方法の後ろに付いているNSを発見しましたか?AVAILABLE_IOS(9_0)、iOS 9がサポートを開始したばかりで、気まずい思いをしました.iOS 9の前にどのように手動でこのニーズを実現するかを分析しながら、実装手順をリストし始めました.
  • cellを長押ししてドラッグモード
  • に入る
  • 現在のcellを非表示にし、collectionView上の
  • に現在のcellのスクリーンショットを追加します.
  • ジェスチャーに従ってスクリーンショットを移動し、スクリーンショットのcenterが別のcell 2の範囲内に入ると、隠されたcellをcell 2の位置に移動し、cell 2およびcell 2の後のcell
  • を移動する.
  • 移動を続けると(3)
  • が実行する.
  • 指を離す移動を終了すると、スクリーンショットが除去され、前に隠すcell
  • が表示する.
    プロセスが順調になったら、次はコードの実現です.
    1.cellを長押ししてドラッグモードに入る
    ここではcollectionViewにロングプッシュジェスチャーを直接追加しました
    UILongPressGestureRecognizer *longG = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPress:)];
    longG.minimumPressDuration = 0.2f;
    [self.collectionView addGestureRecognizer:longG];
    
    - (void)longPress:(UILongPressGestureRecognizer *)lpGesture
    {
        switch(lpGesture.state) {
            case UIGestureRecognizerStateBegan:
            {
                [self collectionViewCellDidBeginChange:lpGesture];
                break;
            }
            case UIGestureRecognizerStateChanged:
            {
                [self collectionViewCellDidChange:lpGesture];
                break;
            }
            case UIGestureRecognizerStateEnded:
            {
                [self collectionViewCellDidEndChange:lpGesture];
                break;
            }
            default:
                if (AVAILABLE_IOS_9_0)
                {
                    [self.collectionView cancelInteractiveMovement];
                }
                break;
        }
    }
    

    2.現在のcellを非表示にし、現在のcellのスクリーンショットをcollectionViewに追加
    - (void)collectionViewCellDidBeginChange:(UILongPressGestureRecognizer *)lpGesture
    {
        self.beginIndexPath = [self.collectionView indexPathForItemAtPoint:[lpGesture locationInView:self.collectionView]];
        self.beginCell = (CollectionViewCell *)[self.collectionView cellForItemAtIndexPath:self.beginIndexPath];
        
        if (AVAILABLE_IOS_9_0)
        {
            [self.collectionView beginInteractiveMovementForItemAtIndexPath:self.beginIndexPath];
        }
        else
        {
            //          cell
            self.tempView = [self.beginCell snapshotViewAfterScreenUpdates:YES];
            self.tempView.frame = self.beginCell.frame;
            [self.collectionView addSubview:self.tempView];
            
            self.beginPoint = [lpGesture locationInView:self.collectionView];
            self.beginCell.hidden = YES;
        }
    }
    
    

    3.スクリーンショットの移動
    - (void)collectionViewCellDidChange:(UILongPressGestureRecognizer *)lpGesture
    {
        CGPoint targetPosion = [lpGesture locationInView:lpGesture.view];
        
        if (AVAILABLE_IOS_9_0)
        {
            [self.collectionView updateInteractiveMovementTargetPosition:targetPosion];
        }
        else
        {
            CGFloat tranX = [lpGesture locationOfTouch:0 inView:self.collectionView].x - self.beginPoint.x;
            CGFloat tranY = [lpGesture locationOfTouch:0 inView:self.collectionView].y - self.beginPoint.y;
            
            //         
            self.tempView.center = CGPointApplyAffineTransform(self.tempView.center, CGAffineTransformMakeTranslation(tranX, tranY));
            self.beginPoint = [lpGesture locationOfTouch:0 inView:_collectionView];
            
            //          cell  
            for (UICollectionViewCell *cell in [_collectionView visibleCells])
            {
                //     cell
                if ([_collectionView indexPathForCell:cell] == self.beginIndexPath)
                {
                    continue;
                }
                //     
                CGFloat space = sqrtf(pow(self.tempView.center.x - cell.center.x, 2) + powf(self.tempView.center.y - cell.center.y, 2));
                
                //           Y              
                if (space <= self.tempView.bounds.size.width * 0.5 && (fabs(self.tempView.center.y - cell.center.y) <= self.tempView.bounds.size.height * 0.5))
                {
                    NSIndexPath *nextIndexPath = [_collectionView indexPathForCell:cell];
                    
                    [self updateDataWithSourceIndexPath:self.beginIndexPath toIndexPath:nextIndexPath];
                    
                    [_collectionView moveItemAtIndexPath:self.beginIndexPath toIndexPath:nextIndexPath];
                    
                    //        indexPath
                    self.beginIndexPath = nextIndexPath;
                    
                    break;
                }
            }
        }
    }
    

    データソースの変更
    - (void)updateDataWithSourceIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
    {
        if (sourceIndexPath.section == destinationIndexPath.section) //     section    
        {
            if (destinationIndexPath.item > sourceIndexPath.item) {
                for (NSUInteger i = sourceIndexPath.item; i < destinationIndexPath.item ; i ++) {
                    [self.dataArray[sourceIndexPath.section] exchangeObjectAtIndex:i withObjectAtIndex:i + 1];
                }
            }else{
                for (NSUInteger i = sourceIndexPath.item; i > destinationIndexPath.item ; i --) {
                    [self.dataArray[sourceIndexPath.section] exchangeObjectAtIndex:i withObjectAtIndex:i - 1];
                }
            }
        }
        else //    section      ,     sourceData,     destinationData
        {
            NSMutableArray *sourceArr = self.dataArray[sourceIndexPath.section];
            NSMutableArray *destinationArr = self.dataArray[destinationIndexPath.section];
            
            id obj = [sourceArr objectAtIndex:sourceIndexPath.row];
            
            [sourceArr removeObjectAtIndex:sourceIndexPath.row];
            
            [destinationArr insertObject:obj atIndex:destinationIndexPath.row];
        }
        
    }
    

    4.移動を続けると(3)
    5.指を離して移動を終了すると、スクリーンショットが除去され、以前に隠していたcellが表示されます
    - (void)collectionViewCellDidEndChange:(UILongPressGestureRecognizer *)lpGesture
    {
        if (AVAILABLE_IOS_9_0)
        {
            [self.collectionView endInteractiveMovement];
        }
        else
        {
            [UIView animateWithDuration:0.25 animations:^{
                
                self.tempView.center = self.beginCell.center;
                
            }completion:^(BOOL finished) {
                
                [self.tempView removeFromSuperview];
                self.beginCell.hidden = NO;
            }];
        }
    }
    

    はい、これでiOS 9以下の適合が完成しました.実現も複雑ではありません.主に実現する前に構想を整理しておけば、実現は難しくありません.
    詳細なコードはgitbubアドレスを参照してください.収穫があれば、starを歓迎します!