You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现UICollectionViewCell选中时内容展开的丝滑动画效果

实现UICollectionViewCell选中卡片展开动画(类App Store效果)

现有代码问题分析

  • 总动画时长长达2.1s,远超系统交互动画的常规时长(一般0.3~0.6s),拖沓感明显
  • 连续嵌套的UIView基础动画没有使用弹性曲线/关键帧动画API,动画节奏不符合物理直觉
  • 动画没有和原UICollectionViewCell的位置、尺寸做绑定,没有从对应单元格展开的连贯感,自然和App Store效果有差距
  • present调用时机放在动画之后,逻辑顺序错误,会出现视图先闪再动画的问题

优化实现方案

1. 自定义转场动画实现(推荐,最贴合App Store效果)

App Store的卡片展开效果本质是自定义模态转场,需要遵守UIViewControllerAnimatedTransitioning协议,把原cell的位置作为动画的起点,实现无缝衔接:
首先在didSelectItemAtIndexPath方法内获取选中cell的位置,给弹出控制器配置转场参数:

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    // 获取选中的cell,转换坐标得到动画起始frame
    UICollectionViewCell *selectedCell = [collectionView cellForItemAtIndexPath:indexPath];
    CGRect originFrame = [collectionView convertRect:selectedCell.frame toView:self.view];
    
    AnimateStaticImageViewController *animateImageVC = [[AnimateStaticImageViewController alloc] init];
    animateImageVC.modalPresentationStyle = UIModalPresentationFullScreen;
    animateImageVC.modelImage = [UIImage imageNamed:text];
    // 给AnimateStaticImageViewController新增两个属性,存储动画起始frame和对应的cell图片
    animateImageVC.originFrame = originFrame;
    // 设置转场代理,当前控制器需遵守UIViewControllerTransitioningDelegate协议
    animateImageVC.transitioningDelegate = self;
    
    [self presentViewController:animateImageVC animated:YES completion:nil];
}

实现转场代理方法,返回自定义动画器:

// 入场动画代理
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
    return [[CardPresentAnimator alloc] init];
}
// 退场动画代理,如果需要收回时也有连贯效果可实现对应的CardDismissAnimator
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
    return [[CardDismissAnimator alloc] init];
}

入场动画器CardPresentAnimator实现:

@implementation CardPresentAnimator
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
    return 0.5; // 时长和系统交互动画对齐,避免违和感
}

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIView *containerView = transitionContext.containerView;
    [containerView addSubview:toVC.view];
    
    AnimateStaticImageViewController *targetVC = (AnimateStaticImageViewController *)toVC;
    CGRect startFrame = targetVC.originFrame;
    CGRect endFrame = containerView.bounds;
    
    // 初始状态和原cell完全对齐,做到无缝衔接
    toVC.view.frame = startFrame;
    toVC.view.layer.cornerRadius = 12; // 和cell的圆角参数保持一致
    toVC.view.clipsToBounds = YES;
    
    // 用弹性动画模拟App Store的回弹效果
    [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0 usingSpringWithDamping:0.8 initialSpringVelocity:0.5 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        toVC.view.frame = endFrame;
        toVC.view.layer.cornerRadius = 0; // 全屏后圆角归零
    } completion:^(BOOL finished) {
        [transitionContext completeTransition:!transitionContext.transitionWasCancelled];
    }];
}
@end

2. 简化优化方案(无需自定义转场)

如果暂时不需要退场联动、手势交互等能力,可以直接优化现有动画的参数,大幅提升流畅度:

AnimateStaticImageViewController *animateImageVC = [[AnimateStaticImageViewController alloc] init];
animateImageVC.modalPresentationStyle = UIModalPresentationFullScreen;
animateImageVC.modelImage = [UIImage imageNamed:text];
// 先设置初始状态
animateImageVC.view.transform = CGAffineTransformMakeScale(0.92, 0.92);
animateImageVC.view.alpha = 0;
// 先弹出控制器再执行动画,避免闪屏
[self presentViewController:animateImageVC animated:NO completion:nil];

// 单次弹性动画替代三层嵌套动画
[UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:0.85 initialSpringVelocity:0.3 options:UIViewAnimationOptionCurveEaseInOut animations:^{
    animateImageVC.view.transform = CGAffineTransformIdentity;
    animateImageVC.view.alpha = 1;
} completion:nil];

效果优化小贴士

  • 确保cell内的图片和弹出控制器内的图片裁剪规则、显示比例完全一致,避免动画过程中出现图片跳变
  • 如果当前页面有导航栏、标签栏,可以在动画过程中同步做隐藏过渡,提升整体连贯感
  • 圆角、阴影的变化要和尺寸变化同步,避免出现生硬的视觉突变

内容的提问来源于stack exchange,提问作者Imran Rony

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 23:24:03