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
相关产品推荐
相关产品推荐

