iphone - UICollectionView 的奇怪动画行为(插入和删除项目)

标签 iphone ios uitableview ios6 uicollectionview

<分区>

当从 UICollectionView 中插入或删除项目时,在动画过程中似乎出现了一个额外的单元格,并且这个额外的单元格向错误的方向移动。我已经用 UITableView 进行了完全相同的尝试,没有问题。

问题视频在这里:https://dl.dropbox.com/u/11523469/CollectionViewBug.mov ,左边是 Collection View ,右边是 TableView 。每个单元格中的数字是创建单元格时单元格的indexPath.item值。

问题首先在视频的 0:08 到 0:12(插入)之间出现,然后在 0:16 到 0:20(删除)再次出现。

项目在这里可用:https://dl.dropbox.com/u/11523469/CollectionViewBug.zip

即插入单元格时,插入单元格下方的所有单元格都会向下移动以为新单元格腾出空间。但是这个额外的单元格出现并与其他单元格重叠并向上移动。

同样,当删除一个单元格时,被删除单元格下方的所有单元格都会向上移动以填充该单元格原来所在的空隙。但是这个额外的单元格出现并与其他单元格重叠并向下移动。

对 Collection View 执行的第一个操作,无论是插入还是删除,都不会导致这个问题。但在所有后续操作中,问题都存在。

有没有其他人遇到过与 UICollectionView 相同的问题?有人有解决方案或解决方法吗?

谢谢!

最佳答案

我想出了一个解决方法,它似乎可以解决问题,但对所提供的示例非常具体。我的猜测是,当单元格被重用时,它们的起点错误,这会导致出现奇怪的动画。

我更改了 Storyboard以使用 UICollectionViewFlowLayout 的子类:

// MyFlowLayout - subclass of UICollectionViewFlowLayout

#import "MyFlowLayout.h"

@interface MyFlowLayout ()

@property (strong) NSMutableArray *deleteIndexPaths;
@property (strong) NSMutableArray *insertIndexPaths;
@property (assign) float rowOffset;

@end

@implementation MyFlowLayout

-(id)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super initWithCoder:aDecoder])
    {
        // minimumInteritemSpacing may be adjusted upwards but this example ignores that
        self.rowOffset = self.itemSize.height + self.minimumInteritemSpacing;
    }

    return self;
}

// As per Mark Pospesel corrections to CircleLayout

- (void)prepareForCollectionViewUpdates:(NSArray *)updateItems
{
    // Keep track of insert and delete index paths
    [super prepareForCollectionViewUpdates:updateItems];

    self.deleteIndexPaths = [NSMutableArray array];
    self.insertIndexPaths = [NSMutableArray array];

    for (UICollectionViewUpdateItem *update in updateItems)
    {
        if (update.updateAction == UICollectionUpdateActionDelete)
        {
            [self.deleteIndexPaths addObject:update.indexPathBeforeUpdate];
        }
        else if (update.updateAction == UICollectionUpdateActionInsert)
        {
            [self.insertIndexPaths addObject:update.indexPathAfterUpdate];
        }
    }
}

- (void)finalizeCollectionViewUpdates
{
    [super finalizeCollectionViewUpdates];
    // release the insert and delete index paths
    self.deleteIndexPaths = nil;
    self.insertIndexPaths = nil;
}

// The next two methods have misleading names as they get called for all visible cells on     both insert and delete

- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath
{
    // Must call super
    UICollectionViewLayoutAttributes *attributes = [super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath];
    if (!attributes)
        attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];

    if ([self.insertIndexPaths containsObject:itemIndexPath]) {
        // Initial position for an inserted cell is it's final position - fades in
        CGRect frame = attributes.frame;
        frame.origin.y = itemIndexPath.row * self.rowOffset;
        attributes.frame = frame;
        attributes.zIndex = -1; // stop the inserted cell bleeding through too early in the animation
    }
    if ([self.deleteIndexPaths count]) {
        NSIndexPath *deletedPath = self.deleteIndexPaths[0];  // Might be more than one but this example ignores that
        if (itemIndexPath.row > deletedPath.row) {
            // Anything after the deleted cell needs to slide up from the position below it's final position
            // Anything before the deleted cell doesn't need adjusting
            CGRect frame = attributes.frame;
            frame.origin.y = ((itemIndexPath.row + 1) * self.rowOffset);
            attributes.frame = frame;
        }
    }

    return attributes;
}

- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath
{
    UICollectionViewLayoutAttributes *attributes = [super finalLayoutAttributesForDisappearingItemAtIndexPath:itemIndexPath];
    if (!attributes)
        attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];

    // I would have expected the final positions to already be correct but my guess is that re-used cells
    // are not considered until after the animation block settings have been generated
    CGRect frame = attributes.frame;
    frame.origin.y = itemIndexPath.row * self.rowOffset;
    attributes.frame = frame;

    if ([self.deleteIndexPaths containsObject:itemIndexPath]) {
        // Fade out the deleted cell
        attributes.alpha = 0.0;
    }

    return attributes;
}

@end

关于iphone - UICollectionView 的奇怪动画行为(插入和删除项目),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14506139/

相关文章:

ios - 如何添加 UIPickerView 部分?

objective-c - 自定义 UITableViewCell with reuseIdentifier without Style?

iphone - 处理子 UIScrollView 中的触摸事件

ios - 如何在 iPhoneSimulator 中识别 iOS 8 和 iOS 9 模拟器?

ios - UITableView - 在不同设备上显示不同的图像尺寸

ios - 如何了解我是否已经为应用内购买付款

ios - iPad 上的空应用程序图标仅适用于 iPhone 应用程序

iphone - 在 iPhone 中拍摄图像时,如何在相机中显示虹膜(有人说快门)?

uitableview - 在手动创建的部分中对核心数据 tableView 行进行分组

ios - 快速具有多个部分的 TableView