Ios UICollectionVIew:设置单元格滚动时的动画

Ios UICollectionVIew:设置单元格滚动时的动画,ios,objective-c,uikit,core-animation,uicollectionview,Ios,Objective C,Uikit,Core Animation,Uicollectionview,我希望在用户滚动列表时,将我的UICollectionView中的项目设置为动画以查看(我使用的是UICollectionViewFlowLayout的子类) 我在布局管理器中指定位置,我希望能够同时指定初始变换,并在正确的时间(当单元格首次出现在屏幕上时)将其应用于动画中。要了解其效果,请查看iOS上的Google Plus应用程序。理想情况下,根据单元的位置进行不同的变换 我似乎找不到一种方法来确定何时显示单元格(没有类似于UITableView上显示的willDisplayCell),也找

我希望在用户滚动列表时,将我的
UICollectionView
中的项目设置为动画以查看(我使用的是
UICollectionViewFlowLayout
的子类)

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

我似乎找不到一种方法来确定何时显示单元格(没有类似于
UITableView
上显示的
willDisplayCell
),也找不到指向该单元格的任何指针

有什么建议吗

在这个屏幕截图中,您可以在Google Plus中制作动画:


另外,看看iPad上的iPhoto。我不知道他们是否在使用UIcollectionView(可能不是,因为它在iOS5上工作),但这就是我要寻找的排序效果,照片似乎从右侧飞入。

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

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

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


要在向下滚动集合视图时将变换应用于单元格,我将考虑直接将变换应用于单元格(在
cellForItem
..)或布局属性中,可能是一个名为
initialTransform
的属性。将布局属性应用于单元格时,您需要检查
初始转换,应用它,然后将其设置为identity,然后触发动画以转到identity转换,因此仅当单元格第一次滚动到屏幕上时才会应用它。我还没有实现任何类似的功能,只是猜测我将如何实现

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

动画代码应该放在
collectionView:cellForItemAtIndexPath:

当一个单元格退出队列时,它的
框架将设置为布局中指定的内容。您可以将其存储在临时变量中,作为单元格的最终
帧。然后可以将
单元格.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
上对来自屏幕顶部和任意一侧的单元格设置动画。您还可以检查当前的
索引XPath
,使单元格在更复杂的布局上从不同位置设置动画,以及随帧设置其他属性的动画,或者应用变换。

正如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;
        }];
    }
}

如果我在这里设置断点,它只在屏幕旋转时被调用。标题注释似乎也表明了这一点。是否还有其他需要配置的内容?我正在对UICollectionViewFlowLayout进行子类化。在向视图中添加项目或滚动时应调用该方法。根据文档,在数据更改或需要重新绘制集合视图时调用该方法,而不是在滚动时调用,除非我做错了什么?您能否确认在滚动时触发了此回调?Quote“当集合视图中的数据发生更改并且要插入或删除项目时,集合视图会要求其布局对象更新布局信息。”从您的话中可以看出,我非常抱歉。我的答案中的方法只有在将单元格添加到集合视图时才有用,我关于滚动的评论是错误的。作为第一步,我将考虑在cellForItemAtIndexPath中应用转换,您可能必须将其作为单元格上的属性,并在applyLayoutAttributes中应用它(在super完成其工作后)。谢谢-我想我会发疯的:o)嘿,您最终得到了答案吗?我正在尝试实现相同的行为,将感谢您的帮助。不,抱歉-我最终使用了标准的滚动视图。@JackKapow,我在下面发布了一个可能有用的答案。@JackKapow我可能在一段时间内没有机会测试这个,所以如果您尝试一下,它会起作用,在这里让我知道,我会把它标记为已接受的答案。好的,我检查过了!非常好用,谢谢!嘿谢谢我玩了一会儿,现在它看起来很棒!我会让你知道如果我发现任何问题,谢谢!!!!你有没有办法让它只动画一次?我的意思是,当我第一次向下滚动时,我想让它动画化——然后我只想让新的细胞动画化(就像谷歌+),我知道你的意思。在Google+中,当新内容插入CollectionView数据源时,可能发生的事情是他们正在制作动画。为了防止在滚动时再次设置动画,我想您需要存储一个标志数组,并为每个已设置动画的indexPath设置它们的值。当为给定的indexPath对一个单元格进行出列时,你会检查该数组,看看是否应该设置动画。是的,我做了一些你说的事情,效果很好!实际上,当新数据到达数据源时,不需要设置动画,因为我使用的是单元格的消隐-单元格实际上是在滚动时加载的,所以我只跟踪已经加载的单元格。再次感谢@塞萨尔超级酒店
-(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) {
                     }];
}