UICollectionVIew:在滚动时为单元格设置动画

Posted

技术标签:

【中文标题】UICollectionVIew:在滚动时为单元格设置动画【英文标题】:UICollectionVIew: Animate cells as they scroll in 【发布时间】:2013-07-20 17:50:43 【问题描述】:

我希望我的UICollectionView 中的项目在用户滚动列表时进行动画查看(我使用的是UICollectionViewFlowLayout 的子类)。

我在布局管理器中指定位置,我希望能够指定一个初始变换并在正确的时间(当单元格首次出现在屏幕上时)将其应用于动画。要查看我的意思,请查看 ios 上的 Google Plus 应用程序。理想情况下,根据单元格的位置进行不同的变换。

我似乎无法找到一种方法来找出何时显示单元格(不等同于 willDisplayCell,就像在 UITableView 上一样)或任何指向此位置的指针。

有什么建议吗?

您几乎可以在此屏幕截图中看到 Google Plus 中的动画:

另外,看看 iPad 上的 iPhoto。我不知道他们是否使用了 UIcollectionView(可能不是,因为它在 iOS5 上工作)但这是我正在寻找的那种效果,照片似乎是从右边飞进来的。

【问题讨论】:

嘿,你最终得到了答案吗?我正在尝试实施相同的行为,将感谢您的帮助。 不,抱歉 - 我最终使用了标准滚动视图。 @JackKapow,我在下面发布了一个可能有用的答案。 @JackKapow 我可能暂时没有机会测试这个,所以如果你尝试这个并且它有效,请在此处告诉我,我会将其标记为已接受的答案。跨度> 好的,我查过了!完美的工作感谢分配! 【参考方案1】:

您可以独立于自定义布局来实现此效果。

动画代码应该在collectionView:cellForItemAtIndexPath:里面

当一个单元格出列时,其frame 将设置为您的布局中指定的内容。您可以将它作为单元格的最终frame 存储在一个临时变量中。然后,您可以将cell.frame 设置为屏幕外的初始位置,然后向所需的最终位置设置动画。大致如下:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 

    UICollectionView *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];

    CGRect finalCellFrame = cell.frame;
    //check the scrolling direction to verify from which side of the screen the cell should come.
    CGPoint translation = [collectionView.panGestureRecognizer translationInView:collectionView.superview];
    if (translation.x > 0) 
        cell.frame = CGRectMake(finalCellFrame.origin.x - 1000, - 500.0f, 0, 0);
     else 
        cell.frame = CGRectMake(finalCellFrame.origin.x + 1000, - 500.0f, 0, 0);
    

    [UIView animateWithDuration:0.5f animations:^(void)
        cell.frame = finalCellFrame;
    ];

    return cell;

上面的代码将为水平UICollectionView 上的单元格设置动画,从屏幕顶部和两侧,具体取决于滚动方向。您还可以检查当前的indexPath 以使单元格在更复杂的布局上从不同位置进行动画处理,以及与框架一起为其他属性设置动画,或应用变换。

【讨论】:

嘿!谢谢 !我玩了一下,现在看起来很棒!如果我发现任何问题,我会告诉你,谢谢分配!!!! 你知道如何让它只动画一次吗?我的意思是,当我第一次向下滚动时,我希望它动画 - 然后我只想让新单元格动画(就像在 google + 中一样) 我知道你的意思。在 Google + 中,可能发生的情况是当新内容插入 CollectionView 数据源时它们正在制作动画。为了防止在滚动时再次设置动画,我想您需要存储一组标志并为每个已设置动画的 indexPath 设置它们的值。当为给定的 indexPath 出列单元格时,您将检查该数组以查看是否应该设置动画。 是的,我做了你说的那样,效果很好!实际上,当新数据到达数据源时不需要动画,因为我正在使用单元格的出队 - 单元格实际上是在滚动时加载的,所以我只跟踪已经加载的单元格。再次感谢! @Cezar 超级酷!感谢那!我正在寻找将其放在UICollectionViewLayout initialLayoutAttributesForAppearingItemAtIndexPath: 中的位置,但现在看起来很明显,它应该在您所说的位置。【参考方案2】:

您需要在集合视图布局中覆盖initialLayoutAttributesForAppearingItemAtIndexPath:。在这里,您可以在布局属性项(包括变换)上设置任何属性,这些属性将在单元格出现后动画为实际属性。

如果标准布局属性对象没有为您提供足够的选项,您可以对其进行子类化、添加额外的属性并覆盖单元格上的applyLayoutAttributes: 以获取额外的属性。

这仅在您将单元格添加到集合视图时才有效。

要在向下滚动集合视图时将变换应用于单元格,我会考虑将它们直接应用于单元格(cellForItem...)或布局属性中,也许是一个名为 @987654325 的属性@。将布局属性应用于单元格时,您将检查initialTransform,应用它,然后将其设置为身份,然后触发动画以进行身份​​转换,因此仅在第一次滚动单元格时应用到屏幕上。我还没有实现这样的东西,这只是我会怎么做的猜测。

【讨论】:

如果我在这里设置断点,它只会在屏幕旋转时被调用。标题 cmets 似乎也表明了这一点。还有什么我需要配置的吗?我正在继承 UICollectionViewFlowLayout。 向视图添加项目或滚动时应该调用它。 根据文档,当数据更改或集合视图需要重绘时调用此方法,而不是在滚动时调用 - 除非我做错了什么?你能确认你在滚动时触发了这个回调吗?引用“当collection view中的数据发生变化,需要插入或删除item时,collection view要求其布局对象更新布局信息。”来自developer.apple.com/library/ios/documentation/uikit/reference/… 你说得对,我很抱歉。我的回答中的方法只有在您将单元格添加到集合视图中时才会有所帮助,我关于滚动的评论是错误的。作为第一步,我将研究在 cellForItemAtIndexPath 中应用转换,您可能必须将其作为单元格上的属性并将其应用到 applyLayoutAttributes 中(在 super 完成工作之后)。 谢谢 - 我以为我快疯了 :o)【参考方案3】:

正如 Marc 在评论中提到的,他最终使用了滚动视图,我想展示如何使用标准表格视图来实现。它与在 google+ 中看到的效果不同,但可以轻松调整。

-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath

    static CGFloat duration = .5;
    static NSUInteger xOffset = 50;
    static NSUInteger yOffset = 200;
    if(scrollDirection == STAScrollDirectionDown && lastAnimatedIndex < indexPath.row)
    
        cell.frame = CGRectMake(cell.frame.origin.x - xOffset, cell.frame.origin.y+yOffset, cell.frame.size.width, cell.frame.size.height);
        [UIView animateWithDuration:duration
                         animations:^
            cell.frame = CGRectMake(cell.frame.origin.x + xOffset, cell.frame.origin.y - yOffset, cell.frame.size.width, cell.frame.size.height);
         completion:^(BOOL finished) 
            lastAnimatedIndex = indexPath.row;
        ];
    

就在单元格显示之前,我们为每个单元格分配一个偏移量(可能还有一个旋转),然后我们将其动画化回之前的设置。


一个更令人兴奋的例子:

-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath

    CATransform3D rotation = CATransform3DMakeRotation( (90.0*M_PI)/180, .0, 0.5, 0.5);
    cell.contentView.alpha = 0.8;
    cell.contentView.layer.transform = rotation;
    cell.contentView.layer.anchorPoint = CGPointMake(0, 0.5);

    [UIView animateWithDuration:.5
                     animations:^
                         cell.contentView.layer.transform = CATransform3DIdentity;
                         cell.contentView.alpha = 1;
                         cell.contentView.layer.shadowOffset = CGSizeMake(0, 0);
                      completion:^(BOOL finished) 
                     ];

【讨论】:

我不知道cellWillAppear 抱歉,我的意思是 cellWillDisplay 我只是将名称与 viewWillAppear 混淆了,请查看此图片:postimg.org/image/a2g02xgbl 创建一个新问题,发布您的代码,描述您想要实现的目标以及您所看到的。

以上是关于UICollectionVIew:在滚动时为单元格设置动画的主要内容,如果未能解决你的问题,请参考以下文章

在选择时为 UICollectionView 单元格设置动画

在选择时为 uicollectionview 单元格设置动画

UICollectionView 水平滚动延迟加载单元格

UICollectionView 在滚动时留下空白单元格

选择单元格时 UICollectionView 正在滚动

UICollectionView,单元格选择不起作用,单元格滚动正常