UICollectionView:选择时动画单元格大小更改

时间:2012-12-08 17:51:09

标签: ios swift uicollectionview

我想要做的是更改UICollectionViewCell的大小,并在选择单元格时为该更改设置动画。我已经通过在collectionView: didSelectItemAtIndexPath:中标记一个单元格然后在我的UICollectionView上调用reloadData,显示所选单元格的大小来设法完成该操作。

尽管如此,这种情况一下子发生了,我不知道如何让动画的大小变化。有什么想法吗?

我已经找到了Animate uicollectionview cells on selection,但答案对我来说并不明确,我还没弄清楚它是否也可以帮助我。

9 个答案:

答案 0 :(得分:86)

在Chase Roberts的帮助下,我现在找到了解决问题的方法。我的代码基本上是这样的:

// Prepare for animation

[self.collectionView.collectionViewLayout invalidateLayout];
UICollectionViewCell *__weak cell = [self.collectionView cellForItemAtIndexPath:indexPath]; // Avoid retain cycles
void (^animateChangeWidth)() = ^()
{
    CGRect frame = cell.frame;
    frame.size = cell.intrinsicContentSize;
    cell.frame = frame;
};

// Animate

[UIView transitionWithView:cellToChangeSize duration:0.1f options: UIViewAnimationOptionCurveLinear animations:animateChangeWidth completion:nil];

进一步说明:

  1. 最重要的一步是对您使用的invalidateLayout进行UICollectionView.collectionViewLayout调用。如果你忘了它,很可能会发生细胞会在你的集合的边界上生长 - 这是你最不希望发生的事情。还要考虑您的代码应该在某个时候向您的布局显示单元格的新大小。在我的情况下(我正在使用UICollectionViewFlowLayout),我调整了collectionView:layout:sizeForItemAtIndexPath方法以反映修改后的单元格的新大小。忘掉那部分,如果你先打电话invalidateLayout然后尝试设置大小变化的动画,那么你的单元格大小就不会发生任何变化。

  2. 最奇怪的是(至少对我而言)但重要的是你在动画块中调用invalidateLayout 而不是。如果这样做,动画将不会显示平滑但有毛刺和闪烁。

  3. 您必须使用单元格作为UIView的参数调用transitionWithView:duration:options:animations:completion: s transitionWithView方法,而不是整个集合视图,因为它是您想要设置动画的单元格,不是整个系列。

  4. 我使用单元格的intrinsicContentSize方法返回我想要的大小 - 在我的情况下,我增长并缩小单元格的宽度,以显示按钮或隐藏它,具体取决于细胞的选择状态。

  5. 我希望这能帮助一些人。对我来说,花了几个小时来弄清楚如何使动画正常工作,所以我试图让其他人摆脱这个耗时的负担。

答案 1 :(得分:45)

为集合视图设置动画的大小与对表视图的设置方式相同。如果要为单元格的大小设置动画,请使用反映单元格状态的数据模型(在我的情况下,我只使用一个标志(CollectionViewCellExpanded,CollectionViewCellCollapsed)并相应地返回一个CGSize。

当您调用并清空performBathUpdates调用时,视图会自动设置动画。

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    [collectionView performBatchUpdates:^{
        // append your data model to return a larger size for
        // cell at this index path
    } completion:^(BOOL finished) {

    }];
}

答案 2 :(得分:31)

通过使用-setCollectionViewLayout:animated:创建相同集合视图布局的新实例,我已成功制作动画更改动画。

例如,如果您使用的是UICollectionViewFlowLayout,那么:

// Make sure that your datasource/delegate are up-to-date first

// Then animate the layout changes
[collectionView setCollectionViewLayout:[[UICollectionViewFlowLayout alloc] init] animated:YES];

答案 3 :(得分:21)

[UIView transitionWithView:collectionView 
                  duration:.5 
                   options:UIViewAnimationOptionTransitionCurlUp 
                animations:^{

    //any animatable attribute here.
    cell.frame = CGRectMake(3, 14, 100, 100);

} completion:^(BOOL finished) {

    //whatever you want to do upon completion

}];

didselectItemAtIndexPath方法中使用这些内容。

答案 4 :(得分:14)

这是我发现的最简单的解决方案 - 就像魅力一样。平滑的动画,并不会弄乱布局。

夫特

    collectionView.performBatchUpdates({}){}

的OBJ-C

    [collectionView performBatchUpdates:^{ } completion:^(BOOL finished) { }];

块(Swift中的闭包)应该故意留空!

答案 5 :(得分:7)

设置单元格大小动画的好方法是在collectionViewCell本身中覆盖isSelected。

class CollectionViewCell: UICollectionViewCell {

    override var isHighlighted: Bool {
        didSet {
            if isHighlighted {
                UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseOut, animations: {
                    self.transform = CGAffineTransform(scaleX: 0.95, y: 0.95)
                }, completion: nil)
            } else {
                UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseOut, animations: {
                    self.transform = CGAffineTransform(scaleX: 1, y: 1)
                }, completion: nil)
            }
        }
    }

}

答案 6 :(得分:5)

使用performBatchUpdates不会为单元格内容的布局设置动画。相反,您可以使用以下内容:

    collectionView.collectionViewLayout.invalidateLayout()

    UIView.animate(
        withDuration: 0.4,
        delay: 0.0,
        usingSpringWithDamping: 1.0,
        initialSpringVelocity: 0.0,
        options: UIViewAnimationOptions(),
        animations: {
            self.collectionView.layoutIfNeeded()
        },
        completion: nil
    )

这给出了一个非常流畅的动画。

这与Ignatius Tremor的答案类似,但转换动画对我来说无法正常工作。

有关完整的解决方案,请参阅https://github.com/cnoon/CollectionViewAnimations

答案 7 :(得分:2)

这对我有用。

    collectionView.performBatchUpdates({ () -> Void in
        let ctx = UICollectionViewFlowLayoutInvalidationContext()
        ctx.invalidateFlowLayoutDelegateMetrics = true
        self.collectionView!.collectionViewLayout.invalidateLayoutWithContext(ctx)
    }) { (_: Bool) -> Void in
    }

答案 8 :(得分:0)

class CollectionViewCell: UICollectionViewCell {
   override var isHighlighted: Bool {
       if isHighlighted {
            UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseInOut, animations: {
                self.transform = CGAffineTransform(scaleX: 0.95, y: 0.95)
            }) { (bool) in
                UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseInOut, animations: {
                    self.transform = CGAffineTransform(scaleX: 1, y: 1)
                }, completion: nil)
            }
        }
   }
}

只需检查isHighlighted变量是否已更改为true,然后使用UIView动画并在完成处理程序中进行动画处理。