21

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

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

我似乎无法找到一种方法来找出何时显示单元格(不等同于willDisplayCellas there is on UITableView)或任何指向此位置的指针。

有什么建议么?

您可以在此屏幕截图中制作 Google Plus 中的动画: Google Plus 应用中的示例

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

4

3 回答 3

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以使单元格在更复杂的布局上从不同位置进行动画处理,以及将其他属性与框架一起动画化,或应用变换。

于 2014-02-09T20:40:52.963 回答
5

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

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

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

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

于 2013-07-20T18:46:13.823 回答
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) {
                     }];
}
于 2014-05-19T15:54:49.790 回答