如何在锁定其中一些单元格时重新排序 UICollectionView 单元格

Posted

技术标签:

【中文标题】如何在锁定其中一些单元格时重新排序 UICollectionView 单元格【英文标题】:How to reorder UICollectionView cells while locks some of them 【发布时间】:2014-04-28 09:30:27 【问题描述】:

我正在重新排序UICollectionView 单元格,同时锁定了几个项目。当我重新排序未锁定的项目时,锁定的项目也会重新排列。我怎样才能洗牌阵列。?或者我必须修改元素的布局属性?

- (void)collectionView:(UICollectionView *)collectionView itemAtIndexPath:(NSIndexPath *)fromIndexPath willMoveToIndexPath:(NSIndexPath *)toIndexPath 


    PlayingCard *playingCard = [self.deck objectAtIndex:fromIndexPath.item];

    [self.deck removeObjectAtIndex:fromIndexPath.item];

    [self.deck insertObject:playingCard atIndex: toIndexPath.item];


    [collectionView performBatchUpdates:^
        NSIndexPath *deletedItemIndexPath = [NSIndexPath indexPathForRow:fromIndexPath.row inSection:fromIndexPath.section];
        NSIndexPath *insertedItemIndexPath = [NSIndexPath indexPathForRow:newToIndexPath.row inSection:toIndexPath.section];

        [collectionView deleteItemsAtIndexPaths:@[ deletedItemIndexPath ]];
        [collectionView insertItemsAtIndexPaths:@[ insertedItemIndexPath ]];
     completion:^(BOOL finished) 

    ];



- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath 
    PlayingCard *playingCard = [self.deck objectAtIndex:indexPath.item];
    return !playingCard.isLocked;


- (BOOL)collectionView:(UICollectionView *)collectionView itemAtIndexPath:(NSIndexPath *)fromIndexPath canMoveToIndexPath:(NSIndexPath *)toIndexPath 
    return ([self collectionView:collectionView canMoveItemAtIndexPath:fromIndexPath] &&
                    [self collectionView:collectionView canMoveItemAtIndexPath:toIndexPath]);


- (void)invalidateLayoutIfNecessary 
    NSIndexPath *newIndexPath = [self.collectionView indexPathForItemAtPoint:self.currentView.center];
    NSIndexPath *previousIndexPath = self.selectedItemIndexPath;

    if ((newIndexPath == nil) || [newIndexPath isEqual:previousIndexPath]) 
        return;
    

    if ([self.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:canMoveToIndexPath:)] &&
        ![self.dataSource collectionView:self.collectionView itemAtIndexPath:previousIndexPath canMoveToIndexPath:newIndexPath]) 
        return;
    

    self.selectedItemIndexPath = newIndexPath;

    if ([self.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:willMoveToIndexPath:)]) 
        [self.dataSource collectionView:self.collectionView itemAtIndexPath:previousIndexPath willMoveToIndexPath:newIndexPath];
    




- (void)handleLongPressGesture:(UILongPressGestureRecognizer *)gestureRecognizer 
    switch(gestureRecognizer.state) 
        case UIGestureRecognizerStateBegan: 
            NSIndexPath *currentIndexPath = [self.collectionView indexPathForItemAtPoint:[gestureRecognizer locationInView:self.collectionView]];

            if ([self.dataSource respondsToSelector:@selector(collectionView:canMoveItemAtIndexPath:)] &&
               ![self.dataSource collectionView:self.collectionView canMoveItemAtIndexPath:currentIndexPath]) 
                return;
            

            self.selectedItemIndexPath = currentIndexPath;

            if ([self.delegate respondsToSelector:@selector(collectionView:layout:willBeginDraggingItemAtIndexPath:)]) 
                [self.delegate collectionView:self.collectionView layout:self willBeginDraggingItemAtIndexPath:self.selectedItemIndexPath];
            

            UICollectionViewCell *collectionViewCell = [self.collectionView cellForItemAtIndexPath:self.selectedItemIndexPath];

            self.currentView = [[UIView alloc] initWithFrame:collectionViewCell.frame];

            collectionViewCell.highlighted = YES;
            UIImageView *highlightedImageView = [[UIImageView alloc] initWithImage:[collectionViewCell LX_rasterizedImage]];
            highlightedImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
            highlightedImageView.alpha = 1.0f;

            collectionViewCell.highlighted = NO;
            UIImageView *imageView = [[UIImageView alloc] initWithImage:[collectionViewCell LX_rasterizedImage]];
            imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
            imageView.alpha = 0.0f;

            [self.currentView addSubview:imageView];
            [self.currentView addSubview:highlightedImageView];
            [self.collectionView addSubview:self.currentView];

            self.currentViewCenter = self.currentView.center;

            __weak typeof(self) weakSelf = self;
            [UIView
             animateWithDuration:0.3
             delay:0.0
             options:UIViewAnimationOptionBeginFromCurrentState
             animations:^
                 __strong typeof(self) strongSelf = weakSelf;
                 if (strongSelf) 
                     strongSelf.currentView.transform = CGAffineTransformMakeScale(1.1f, 1.1f);
                     highlightedImageView.alpha = 0.0f;
                     imageView.alpha = 1.0f;
                 
             
             completion:^(BOOL finished) 
                 __strong typeof(self) strongSelf = weakSelf;
                 if (strongSelf) 
                     [highlightedImageView removeFromSuperview];

                     if ([strongSelf.delegate respondsToSelector:@selector(collectionView:layout:didBeginDraggingItemAtIndexPath:)]) 
                         [strongSelf.delegate collectionView:strongSelf.collectionView layout:strongSelf didBeginDraggingItemAtIndexPath:strongSelf.selectedItemIndexPath];
                     
                 
             ];

            [self invalidateLayout];
         break;
        case UIGestureRecognizerStateCancelled:
        case UIGestureRecognizerStateEnded: 
            NSIndexPath *currentIndexPath = self.selectedItemIndexPath;

            if (currentIndexPath) 
                if ([self.delegate respondsToSelector:@selector(collectionView:layout:willEndDraggingItemAtIndexPath:)]) 
                    [self.delegate collectionView:self.collectionView layout:self willEndDraggingItemAtIndexPath:currentIndexPath];
                

                self.selectedItemIndexPath = nil;
                self.currentViewCenter = CGPointZero;

                UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForItemAtIndexPath:currentIndexPath];

                __weak typeof(self) weakSelf = self;
                [UIView
                 animateWithDuration:0.3
                 delay:0.0
                 options:UIViewAnimationOptionBeginFromCurrentState
                 animations:^
                     __strong typeof(self) strongSelf = weakSelf;
                     if (strongSelf) 
                         strongSelf.currentView.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
                         strongSelf.currentView.center = layoutAttributes.center;
                     
                 
                 completion:^(BOOL finished) 
                     __strong typeof(self) strongSelf = weakSelf;
                     if (strongSelf) 
                         [strongSelf.currentView removeFromSuperview];
                         strongSelf.currentView = nil;
                         [strongSelf invalidateLayout];

                         if ([strongSelf.delegate respondsToSelector:@selector(collectionView:layout:didEndDraggingItemAtIndexPath:)]) 
                             [strongSelf.delegate collectionView:strongSelf.collectionView layout:strongSelf didEndDraggingItemAtIndexPath:currentIndexPath];
                         
                     
                 ];
            
         break;

        default: break;
    

【问题讨论】:

不安是什么意思? 现在能帮帮我吗? 那么,如果您将一个单元格移动到一个锁定的单元格前面,您期望会发生什么?锁定的牢房显然会移动,而且你不能在同一个地方有两个牢房...... 如果我将单元格移动到锁定单元格的前面,我会检查它是否可以从“fromIndexPath”移动到“toIndexPath”。如果 toIndexPath 上的元素被锁定,它将返回零。 让我们假设。我有 3 件物品。仅中间一个被锁定。我将第三个项目拖到第一个项目上。第一项应位于第三个元素的位置,而不是第二项位置。我不想用第一项替换第三项。 【参考方案1】:

你需要做的是:

当用户移动单元格时,您将该单元格放入新的索引路径(如果要替换的那个没有锁定)。

然后对于已替换的行,您需要将其索引行移动 +1。这可能需要循环完成,您需要检查下一个单元格是否未锁定。如果它被锁定,那么您只需将该行再增加 1。例如:

CELL 1

CELL 2 - locked

CELL 3

我将CELL 3 移动到CELL 1。然后您需要检查CELL 2 是否被锁定。如果是(如本例所示),则将CELL 1 移动到CELL 3

//This is the card that is moving
PlayingCard *cardToMove = [self.deck objectAtIndex:fromIndexPath.row];

//This is the card that is being replaced and also needs to move.
PlayingCard *cardToReplace = [self.deck objectAtIndex:toIndexPath.row];


//We need to check if the next cell is a position which we can occupy with the cardToMove. This is where the loop will go. 
NSInteger increment = 1;

PlayingCard *cardNextToReplaced = [self.deck objectAtIndex:toIndexPath.row + increment];

while (cardNextToReplaced.isLocked) 

    increment ++;
    cardNextToReplaced == [self.deck objectAtIndex:toIndexPath.row + increment];



//This should now be a 'free space'
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:toIndexPath.row + increment inSection:toIndexPath.section];


//So now you just move the cardToMove to it's new index path. The cardToReplace should be moved the newly created `indexPath` above this. That should be a 'free space'.

【讨论】:

修改了我的帖子。 好吧,我不会为你写的。但可以添加一些。等等。

以上是关于如何在锁定其中一些单元格时重新排序 UICollectionView 单元格的主要内容,如果未能解决你的问题,请参考以下文章

在 UITableView (swift2) 中选择单元格时更新/重新加载 ViewController

UIView drawRect 仅在 UITableViewCell 中调用一次,导致重新使用单元格时数据过时

如何使用自定义按钮重新排序表格视图单元格,但不使用 ios 中的移动编辑图标

SQL 导出到 Excel 结果到文档锁定,无法编辑工作表

屏幕旋转后如何在 UICollectionView 中跟踪单元格的移动

重新排序 CollectionView 单元格 iOS 11