19

有没有人看到这个问题的体面答案?

initialLayoutAttributesForAppearingItemAtIndexPath似乎正在为所有可见的单元格调用,而不仅仅是插入的单元格。根据Apple自己的文档

对于移动的项目,集合视图使用标准方法来检索项目的更新布局属性。对于插入或删除的项目,集合视图会调用一些不同的方法,您应该重写这些方法以提供适当的布局信息

这听起来不像正在发生的事情......其他单元格没有被插入,它们正在被移动,但它也要求initialLayoutAttributesForAppearingItemAtIndexPath那些被移动的单元格。

我已经看到使用prepareForCollectionViewUpdates:来跟踪哪些 indexPaths 正在更新并且只更改那些的变通方法,但这似乎有点奇怪,因为它会再次出现在他们自己的文档中。有没有其他人找到解决这个问题的更好方法?

4

4 回答 4

25

我发现Mark Pospesel的这篇博文很有帮助。
作者还修复了 WWDCCircleLayout示例并将其发布在 Github 上

感兴趣的方法:

- (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;
}

// Note: name of method changed
// Also this gets called for all visible cells (not just the inserted ones) and
// even gets called when deleting cells!
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath
{
    // Must call super
    UICollectionViewLayoutAttributes *attributes = [super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath];

    if ([self.insertIndexPaths containsObject:itemIndexPath])
    {
        // only change attributes on inserted cells
        if (!attributes)
            attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];

        // Configure attributes ...
        attributes.alpha = 0.0;
        attributes.center = CGPointMake(_center.x, _center.y);
    }

    return attributes;
}

// Note: name of method changed
// Also this gets called for all visible cells (not just the deleted ones) and
// even gets called when inserting cells!
- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath
{
    // So far, calling super hasn't been strictly necessary here, but leaving it in
    // for good measure
    UICollectionViewLayoutAttributes *attributes = [super finalLayoutAttributesForDisappearingItemAtIndexPath:itemIndexPath];

    if ([self.deleteIndexPaths containsObject:itemIndexPath])
    {
        // only change attributes on deleted cells
        if (!attributes)
            attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];

        // Configure attributes ...
        attributes.alpha = 0.0;
        attributes.center = CGPointMake(_center.x, _center.y);
        attributes.transform3D = CATransform3DMakeScale(0.1, 0.1, 1.0);
    }

    return attributes;
}
于 2013-01-19T19:49:51.267 回答
12

你不是一个人。UICollectionViewLayout 头文件注释让事情变得更清晰一些。

对于失效前屏幕上的每个元素,将调用 finalLayoutAttributesForDisappearingXXX 并设置从屏幕上的内容到最终属性的动画。

对于失效后屏幕上的每个元素,initialLayoutAttributesForAppearingXXX 将被称为从这些初始属性到最终出现在屏幕上的动画设置。

基本上finalLayoutAttributesForDisappearingItemAtIndexPath在动画块开始之前为屏幕上的每个项目initialLayoutAttributesForAppearingItemAtIndexPath调用,并在动画块结束后为每个项目调用。缓存UICollectionViewUpdateItem发送的对象数组由您决定,prepareForCollectionViewUpdates以便您知道如何设置初始属性和最终属性。在我的例子中,我缓存了以前的布局矩形,prepareLayout所以我知道要使用的正确初始位置。

让我难过一阵子的一件事是你应该使用 super 的实现initialLayoutAttributesForAppearingItemAtIndexPath并修改它返回的属性。我只是layoutAttributesForItemAtIndexPath在我的实现中调用,动画不起作用,因为布局位置不同。

于 2012-12-19T21:45:42.627 回答
0

如果你有子类UICollectionViewFlowLayout化,你可以调用super实现。一旦你得到了默认的初始布局,你可以检查一个.alphaof 0。如果alpha不是0,则单元格正在被移动,如果它0正在被插入。

有点hack,我知道,但它有效。

Swift 2.0 实现如下:

override func initialLayoutAttributesForAppearingItemAtIndexPath(itemIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {


    guard let attributes = super.initialLayoutAttributesForAppearingItemAtIndexPath(itemIndexPath) where attributes.alpha == 0 else {
        return nil
    }

    // modify attributes for insertion here

    return attributes

}
于 2015-09-30T23:03:04.417 回答
-1

确保您在 Swift 3 中使用新方法签名。自动更正不适用于此方法:

func initialLayoutAttributesForAppearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes?
于 2017-01-04T17:01:57.907 回答