CollectionViewCell 在自定义动画上旋转

Posted

技术标签:

【中文标题】CollectionViewCell 在自定义动画上旋转【英文标题】:CollectionViewCell gets rotated on custom animation 【发布时间】:2014-04-13 17:10:06 【问题描述】:

编辑:这个 SO 答案似乎解释了我遇到以下问题的原因:UIViewController returns invalid frame?

自定义动画有问题。当点击单元格时,我正在对 viewController 进行模态演示。但是当动画开始时,它会将我的单元格旋转 90 度(如下面的屏幕截图所示)。我最初虽然它与方向有关,但我正在拍摄单元格的快照,所以它不应该真的影响它..?

1 http://foffer.dk/rotation90.png

代码如下:

启动 viewController 并呈现它(PhotosCollectionViewCont.m):

-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
    //Fetch data to display
    NSArray *photosArray = [self.dishes valueForKeyPath:@"dishes.content.image"];
    NSArray *nameArray = [self.dishes valueForKeyPath:@"dishes.content.name"];




    FOFDishDetailViewController *toVC = [[FOFDishDetailViewController alloc] init];
    toVC.view.backgroundColor = [UIColor lightGrayColor];


    [toVC.imageView setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://xx.yy.zz.qq:4000%@",[photosArray objectAtIndex: indexPath.row]]]];
    toVC.nameLabel.text = [NSString stringWithFormat:@"%@", [nameArray objectAtIndex:indexPath.row]];

    toVC.transitioningDelegate = self;
    toVC.modalPresentationStyle = UIModalPresentationCustom;

    [self presentViewController:toVC animated:YES completion:nil];        

    [self collectionView:collectionView didDeselectItemAtIndexPath:indexPath];

还有动画,在同一个 PhotosCollectionViewCont.m 中调用:

-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext

    NSLog(@"context class is %@", [transitionContext class]);

    NSIndexPath *selected = self.collectionView.indexPathsForSelectedItems[0];
    UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:selected];

    UIView *container = transitionContext.containerView;

    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIView *toView = toVC.view;
    UIView *fromView = fromVC.view;


    NSTimeInterval duration = [self transitionDuration:transitionContext];

    CGRect beginFrame = [container convertRect:cell.bounds fromView:cell];

    CGRect endFrame = [transitionContext initialFrameForViewController:fromVC];

    //Remove comment for non-fullscreen
    //endFrame = CGRectInset(endFrame, 40.0, 40.0);
    fromVC.view.alpha = 1.0;
//    toVC.view.alpha = 0.3;

    CGRect mainScreen = [[UIScreen mainScreen] bounds];



    UIView *intermediateView = [cell snapshotViewAfterScreenUpdates:NO];
    intermediateView.frame = cell.frame;
    [container addSubview:intermediateView];

//    [container addSubview:move];

    [UIView animateKeyframesWithDuration:duration
                                   delay:0.0
                                 options:UIViewKeyframeAnimationOptionCalculationModeCubic
                              animations:^


                                  [UIView addKeyframeWithRelativeStartTime:0.0
                                                          relativeDuration:0.5 animations:^

                                                              intermediateView.frame = endFrame;
                                   ];
                                  [UIView addKeyframeWithRelativeStartTime:0.5
                                                          relativeDuration:0.5 animations:^
                                                              fromVC.view.alpha = 0.0;
                                                              toVC.view.alpha = 1.0;
                                                          ];


                               completion:^(BOOL finished) 

                                  toVC.view.frame = mainScreen;
                                  [container addSubview:toView];

                                  [intermediateView removeFromSuperview];
                                  fromVC.view.alpha = 1.0;
                                  [transitionContext completeTransition:YES];
                              ];

我知道动画本身真的很乱,但目前我唯一关心的是摆脱旋转问题。

如果您需要更多代码来帮助我解决此问题,请告诉我,我会提供。

【问题讨论】:

【参考方案1】:

这类似于我在 Landscape 中执行 UIViewControllerTransitioning 时遇到的问题。

就这个过渡而言,无论出于何种原因,肖像中的坐标系。我猜当你在这里拿到单元格时:

UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:selected];

并在此处进行快照:

UIView *intermediateView = [cell snapshotViewAfterScreenUpdates:NO];

单元格是纵向的,而您显然是在横向查看它。解决方案可能相当复杂,但我发现解决此问题的最简单方法是为 UIViewController 创建一个协议,其中包含集合视图。

在此协议中声明一个名为 selectedCellSnapshotView 的只读属性。

/** A snapshot of the selected collection view cell.    */
@property (nonatomic, strong, readonly) UIView *selectedCellSnapshotView;

显然让集合视图采用此协议,并在 getter 中为它执行以下操作:

/**
 * A snapshot of the selected collection view cell.
 *
 *  @return A snapshot of the selected collection view cell.
 */
- (UIView)selectedCellSnapshotView

    UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:self.selectedIndexPath];
    return [cell snapshotViewAfterScreenUpdates:NO];

然后将过渡委托移动到它自己的类中。

虽然这听起来很不合逻辑,但它对我有用,所以我希望它对你有用。

排除整个答案的一个简单方法是它在肖像中转换时的行为是否不同。你只展示了风景的截图,所以我不知道。

我真的希望这在某种程度上有所帮助,如果没有,我很抱歉。

【讨论】:

感谢您的回答@Infinity James,我不知道它是否有帮助,但是当我尝试使用 viewController 启动动画时(即 viewController 从单元格中弹出,它也是旋转了 90 度。我会尝试你的答案,然后回复你:) 哦,顺便说一下,纵向模式时,它显示正确 我找到了这个 SO 答案,我认为这是问题的根本原因:***.com/questions/9539676/… 这就是为什么我建议分离出过渡委托。您希望将 UIViewController 保持在正确的坐标空间中,并且仅通过调用它来获取单元格的快照,它应该以正确的坐标返回单元格。然后 containerView 应该是正确的,因此添加快照应该没问题。

以上是关于CollectionViewCell 在自定义动画上旋转的主要内容,如果未能解决你的问题,请参考以下文章

动画未在自定义布局中显示

在自定义 UIView 上为 UIButton 设置动画

在自定义视图中制作 2 个动画

在 CollectionViewCell 中上移标签动画

在自定义 UIView 中动画 UIBezierPath 不起作用

如何在自定义 UIButton 中实现 .isHighlighted 动画?