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

Ign*_*mor 62 ios uicollectionview swift

我想要做的是更改UICollectionViewCell的大小,并在选择单元格时为该更改设置动画.我已经设法通过将一个单元格标记为选中collectionView: didSelectItemAtIndexPath:,然后调用reloadData我的UICollectionView,显示具有不同大小的所选单元格来实现非动画.

然而,这种情况一下子发生了,我不知道如何让动画的大小变化.有任何想法吗?

我已经在选择中找到了Animate uicollectionview单元格,但答案对我来说并不明确,我还没弄清楚它是否也可以帮助我.

Ign*_*mor 87

在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];
Run Code Online (Sandbox Code Playgroud)

有关进一步说明:

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

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

  3. 您必须使用单元格作为参数调用UIViews transitionWithView:duration:options:animations:completion:方法transitionWithView,而不是整个集合视图,因为它是您要获取动画的单元格,而不是整个集合.

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

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

  • 给读者的一些建议:在单元格中使用AutoLayout可能会破坏这一点.我不得不改变单元格的高度约束,然后在动画块中使用[cell layoutIfNeeded] (3认同)
  • 发布跟进的好工作. (2认同)
  • 关于避免保留周期的部分,不应该在块外面声明*吗?因为你正在使用uicollectionview(iOS 6+),所以现在首选的限定符是`__weak`.如果`block`出现在*块中,则会创建一个强引用,因此您不会避免任何保留周期.不过,非常感谢您的跟进,非常有帮助! (2认同)

And*_*oes 47

动画单元格的大小对于集合视图的工作方式与对表视图的工作方式相同.如果要为单元格的大小设置动画,请使用反映单元格状态的数据模型(在我的示例中,我只使用标志(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) {

    }];
}
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案.在我的情况下,我只需要更改模型,然后调用performBatchUpdates并在块中调用invalidateLayout. (2认同)

jon*_*ley 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];
Run Code Online (Sandbox Code Playgroud)


Cha*_*rts 23

[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

}];
Run Code Online (Sandbox Code Playgroud)

在你的didselectItemAtIndexPath方法中使用这些内容.

  • 它似乎工作但结果在视觉上是可怕的.它似乎停滞不前.有任何想法吗? (2认同)

Pav*_*rov 16

这是我发现的最简单的解决方案 - 就像魅力一样.流畅的动画,并没有弄乱布局.

迅速

    collectionView.performBatchUpdates({}){}
Run Code Online (Sandbox Code Playgroud)

OBJ-C

    [collectionView performBatchUpdates:^{ } completion:^(BOOL finished) { }];
Run Code Online (Sandbox Code Playgroud)

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

  • 我已经在更新块内尝试了“reloadData”、“moveItemAtIndexPath: toIndexPath:”、“reloadItemsAtIndexPaths:”的解决方案,然后意识到该块应该留空。现在真的很有魅力。 (2认同)

Cri*_*ena 9

设置单元格大小动画的好方法是在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)
            }
        }
    }

}
Run Code Online (Sandbox Code Playgroud)


pha*_*ann 6

使用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
    )
Run Code Online (Sandbox Code Playgroud)

这样可以产生非常流畅的动画。

这类似于Ignatius Tremor的答案,但过渡动画对我而言无法正常工作。

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