UICollectionView 单元格的水平重新排序

Posted

技术标签:

【中文标题】UICollectionView 单元格的水平重新排序【英文标题】:Horizontal reordering of UICollectionView cells 【发布时间】:2016-05-25 12:46:05 【问题描述】:

我有一个水平滚动的 UICollectionView。每个单元格对应于数组中的一个对象(货币代码)。我想要的是能够通过拖放手势重新排列单元格。

我为 UITableView 找到了 tutorial 并尝试了它,但是当我按住并拖动一个单元格时,它只会垂直移动,而当我将手指移动到屏幕边缘时它不会滚动。这是gif。

我想要让单元格水平移动,而不是垂直移动,并且在到达屏幕边缘时让集合视图滚动。我将如何实现这一目标?

这就是我现在拥有的:

UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget: self action: @selector(longPressGestureRecognised:)];
[self.collectionView addGestureRecognizer: longPress];


-(IBAction) longPressGestureRecognised:(id)sender

UILongPressGestureRecognizer *longPress = (UILongPressGestureRecognizer *)sender;
UIGestureRecognizerState state = longPress.state;

CGPoint location = [longPress locationInView: self.collectionView];
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint: location];

static UIView *snapshot = nil;
static NSIndexPath *sourceIndexPath = nil;

switch (state) 
    case UIGestureRecognizerStateBegan: 
        if (indexPath) 
            sourceIndexPath = indexPath;

            UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath: indexPath];

            // Take a snapshot of the selected item using helper method.
            snapshot = [self customSnapshotFromView: cell];

            // Add the snapshot as subview, centered at cell's centre.
            __block CGPoint centre = cell.center;
            snapshot.center = centre;
            snapshot.alpha = 0.0;
            [self.collectionView addSubview: snapshot];
            [UIView animateWithDuration: 0.25 animations:^

                // Offset for gesture location.
                centre.y = location.y;
                snapshot.center = centre;
                snapshot.transform = CGAffineTransformMakeScale(1.05, 1.05);
                snapshot.alpha = 0.98;

                // Fade out.
                cell.alpha = 0.0;

             completion: ^(BOOL finished) 
                cell.hidden = YES;
            ];
        
        break;
    

    case UIGestureRecognizerStateChanged: 
        CGPoint centre = snapshot.center;
        centre.y = location.y;
        snapshot.center = centre;

        // Is destination valid and is it different from source?
        if (indexPath && ![indexPath isEqual: sourceIndexPath]) 
            // Update data source.
            [currencyArray exchangeObjectAtIndex: indexPath.item withObjectAtIndex:sourceIndexPath.item];

            // Move the items.
            [self.collectionView moveItemAtIndexPath: sourceIndexPath toIndexPath: indexPath];

            // And update source so it is in sync with UI changes.
            sourceIndexPath = indexPath;
        
        break;
    

    default: 
        // Clean up.
        UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath: sourceIndexPath];
        cell.hidden = NO;
        cell.alpha = 0.0;
        [UIView animateWithDuration: 0.25 animations: ^

            snapshot.center = cell.center;
            snapshot.transform = CGAffineTransformIdentity;
            snapshot.alpha = 0.0;

            // Undo fade out.
            cell.alpha = 1.0;

        completion: ^(BOOL finished) 

            sourceIndexPath = nil;
            [snapshot removeFromSuperview];
            snapshot = nil;

        ];
        break;
    




-(UIView *) customSnapshotFromView:(UIView *)inputView

// Make an image from the input view.
UIGraphicsBeginImageContextWithOptions(inputView.bounds.size, NO, 0);
[inputView.layer renderInContext: UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

// Create an image view.
UIView *snapshot = [[UIImageView alloc] initWithImage: image];
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;

编辑: 我已经想通了。代码如下:

UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget: self action: @selector(handleLongGesture:)];
[self.collectionView addGestureRecognizer: longPress];

-(IBAction) handleLongGesture: (id)sender 
UILongPressGestureRecognizer *longPress = (UILongPressGestureRecognizer *)sender;

CGPoint location = [longPress locationInView: self.collectionView];
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint: location];

switch (longPress.state) 
    case UIGestureRecognizerStateBegan:
        [self.collectionView beginInteractiveMovementForItemAtIndexPath: indexPath];
        NSLog(@"Gesture began");
        break;

    case UIGestureRecognizerStateChanged:
        [self.collectionView updateInteractiveMovementTargetPosition: [longPress locationInView: longPress.view]];
        NSLog(@"Gesture state changed");
        break;

    case UIGestureRecognizerStateEnded:
        [self.collectionView endInteractiveMovement];
        NSLog(@"Gesture state ended");
        break;

    default:
        [self.collectionView cancelInteractiveMovement];
        NSLog(@"Gesture cancelled");
        break;
    

【问题讨论】:

【参考方案1】:

在 UIGestureRecognizerStateChanged 中: 修改这行代码

        CGPoint centre = snapshot.center;
        centre.x = location.x;
        snapshot.center = centre;

center.y 返回 y 轴拖动

将其更改为 center.x 以进行 x 轴拖动

【讨论】:

谢谢你,但我已经解决了。我最终在 UICollectionView 中使用了 interactiveMovement 方法。

以上是关于UICollectionView 单元格的水平重新排序的主要内容,如果未能解决你的问题,请参考以下文章

UICollectionView - 一次一个单元格的水平分页

带有 WKWebView 单元格的滚动 UICollectionView 的 UITableView

如何获取位于 UICollectionView 中心的单元格的 indexPath

旋转后 UICollectionView 单元格不水平

如何水平居中 UICollectionView 单元格?

滚动到 UICollectionView 中的下一个单元格