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

iOS应用中的最大化与缩小动画实现方法咨询

嘿,我之前刚好折腾过类似的iOS窗口缩放动画,给你分享几个实用的实现思路,应该能解决你的问题!

实现iOS视图最大化/缩小动画的几种方案

一、同一ViewController内的视图缩放(最常用)

这种场景适合从一个小卡片/缩略图放大到全屏,再缩小回去的情况,用UIView的基础动画就能搞定,还能加弹簧效果让动画更自然。

核心思路:

  • 先记录小视图的原始位置和样式(比如圆角、阴影)
  • 创建全屏视图(或者用快照视图避免原视图被干扰)
  • 用UIView.animate修改视图的frame、cornerRadius、阴影等属性,实现平滑过渡

代码示例:

// 假设smallCard是你的小视图,fullScreenView是提前准备好的全屏视图(初始隐藏)
func zoomToFullScreen() {
    // 把小视图的坐标转换到父视图坐标系
    let originalFrame = smallCard.convert(smallCard.bounds, to: view)
    
    // 初始化全屏视图的初始状态,和小视图保持一致
    fullScreenView.frame = originalFrame
    fullScreenView.layer.cornerRadius = smallCard.layer.cornerRadius
    fullScreenView.layer.shadowOpacity = smallCard.layer.shadowOpacity
    view.addSubview(fullScreenView)
    
    // 执行动画,用弹簧参数让效果更生动
    UIView.animate(withDuration: 0.35,
                   delay: 0,
                   usingSpringWithDamping: 0.8,
                   initialSpringVelocity: 0.6,
                   options: .curveEaseInOut) {
        // 切换到全屏状态
        self.fullScreenView.frame = self.view.bounds
        self.fullScreenView.layer.cornerRadius = 0
        self.fullScreenView.layer.shadowOpacity = 0 // 全屏时去掉阴影
    } completion: { _ in
        // 动画完成后隐藏小视图
        self.smallCard.isHidden = true
    }
}

// 缩小回去的逆向动画
func shrinkToSmallCard() {
    let targetFrame = smallCard.convert(smallCard.bounds, to: view)
    
    UIView.animate(withDuration: 0.35,
                   delay: 0,
                   usingSpringWithDamping: 0.8,
                   initialSpringVelocity: 0.6,
                   options: .curveEaseInOut) {
        self.fullScreenView.frame = targetFrame
        self.fullScreenView.layer.cornerRadius = self.smallCard.layer.cornerRadius
        self.fullScreenView.layer.shadowOpacity = self.smallCard.layer.shadowOpacity
    } completion: { _ in
        self.fullScreenView.removeFromSuperview()
        self.smallCard.isHidden = false
    }
}

注意点:

如果你的小视图是CollectionView/TableView的Cell,直接用原视图做动画可能会因为cell复用出问题,这时候可以用快照视图替代:

// 创建小视图的快照
let snapshot = smallCard.snapshotView(afterScreenUpdates: true)!
snapshot.frame = originalFrame
snapshot.layer.cornerRadius = smallCard.layer.cornerRadius
view.addSubview(snapshot)
smallCard.isHidden = true

// 对快照做动画,完成后移除快照并显示全屏视图

二、ViewController之间的转场动画

如果是从一个VC跳转到另一个VC时需要这种缩放效果,就需要自定义转场动画,实现UIViewControllerAnimatedTransitioning协议。

代码示例:

class ZoomTransition: NSObject, UIViewControllerAnimatedTransitioning {
    private let isPresenting: Bool
    private let originFrame: CGRect // 小视图的原始frame
    
    init(isPresenting: Bool, originFrame: CGRect) {
        self.isPresenting = isPresenting
        self.originFrame = originFrame
        super.init()
    }
    
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.35
    }
    
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let container = transitionContext.containerView
        guard let toVC = transitionContext.viewController(forKey: .to),
              let fromVC = transitionContext.viewController(forKey: .from) else {
            transitionContext.completeTransition(false)
            return
        }
        
        if isPresenting {
            // 跳转时:把目标VC的视图先缩放到小视图的位置
            toVC.view.frame = originFrame
            toVC.view.layer.cornerRadius = 16 // 匹配小视图的圆角
            container.addSubview(toVC.view)
            
            UIView.animate(withDuration: transitionDuration(using: transitionContext),
                           delay: 0,
                           usingSpringWithDamping: 0.8,
                           initialSpringVelocity: 0.6) {
                toVC.view.frame = container.bounds
                toVC.view.layer.cornerRadius = 0
            } completion: { _ in
                transitionContext.completeTransition(true)
            }
        } else {
            // 返回时:把当前VC的视图缩回到小视图位置
            UIView.animate(withDuration: transitionDuration(using: transitionContext),
                           delay: 0,
                           usingSpringWithDamping: 0.8,
                           initialSpringVelocity: 0.6) {
                fromVC.view.frame = self.originFrame
                fromVC.view.layer.cornerRadius = 16
            } completion: { _ in
                fromVC.view.removeFromSuperview()
                transitionContext.completeTransition(true)
            }
        }
    }
}

如何使用:

在发起跳转的VC里,设置transitioningDelegate,并实现对应的方法:

class OriginVC: UIViewController, UIViewControllerTransitioningDelegate {
    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        // 这里传入小视图的frame
        let originFrame = smallCard.convert(smallCard.bounds, to: view)
        return ZoomTransition(isPresenting: true, originFrame: originFrame)
    }
    
    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        let originFrame = smallCard.convert(smallCard.bounds, to: view)
        return ZoomTransition(isPresenting: false, originFrame: originFrame)
    }
    
    // 跳转时设置delegate
    func goToFullScreenVC() {
        let fullScreenVC = FullScreenVC()
        fullScreenVC.transitioningDelegate = self
        fullScreenVC.modalPresentationStyle = .fullScreen
        present(fullScreenVC, animated: true)
    }
}

三、进阶:用Core Animation实现更复杂的效果

如果需要更精细的控制(比如3D缩放、阴影渐变),可以直接用CABasicAnimation修改图层的transform、cornerRadius等属性,不过上手难度稍高,适合有一定Core Animation基础的开发者。

比如实现3D缩放:

let scaleAnimation = CABasicAnimation(keyPath: "transform")
scaleAnimation.fromValue = CATransform3DMakeScale(0.8, 0.8, 1.0)
scaleAnimation.toValue = CATransform3DIdentity
scaleAnimation.duration = 0.35

let cornerRadiusAnimation = CABasicAnimation(keyPath: "cornerRadius")
cornerRadiusAnimation.fromValue = 16
cornerRadiusAnimation.toValue = 0
cornerRadiusAnimation.duration = 0.35

let animationGroup = CAAnimationGroup()
animationGroup.animations = [scaleAnimation, cornerRadiusAnimation]
animationGroup.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
animationGroup.duration = 0.35

fullScreenView.layer.add(animationGroup, forKey: "zoomAnimation")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:27:20