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

时间:2013-07-20 17:50:43

标签: ios objective-c uikit core-animation uicollectionview

我希望UICollectionView中的项目可以动画显示,因为用户滚动列表(我正在使用UICollectionViewFlowLayout的子类)。

我在布局管理器中指定位置,我希望能够做的是指定一个初始变换,并在正确的时间(当单元格首次出现在屏幕上时)应用于动画中。要查看我的意思,请查看iOS上的Google Plus应用。理想情况下,不同的变换取决于细胞的位置。

我似乎无法找到一种方法来查明何时显示一个单元格(不等同于willDisplayCell上的UITableView)或任何有关此位置的指针。< / p>

有什么建议吗?

您可以在此屏幕截图中了解Google Plus中的动画: Example in the Google Plus App

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

3 个答案:

答案 0 :(得分:36)

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

动画代码应该放在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以使单元格在更复杂的布局上从不同位置设置动画,以及为框架设置其他属性的动画,或应用变换。

答案 1 :(得分:5)

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

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

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

要在向下滚动集合视图时将变换应用于单元格,我会将它们直接应用于单元格(cellForItem ...)或布局属性,也许是一个名为initialTransform。将布局属性应用于单元格时,您需要检查initialTransform,应用它,然后将其设置为标识,然后触发动画转到标识转换,因此只有在单元格为首先滚动到屏幕上。我没有实现这样的任何东西,它只是猜测我将如何做到这一点。

答案 2 :(得分: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) {
                     }];
}