iOS的原生应用都是设计师和工程师精心设计的,Weather的scrollview滚动动画,Settting的interaction交互式动画,App Store的Card过渡动画等等。都有很多我们值得学习的地方,今天我们模拟App Store的卡片动画
App Store动画模拟学习参考教程
自定义过渡动画教程
如何实现自定义过渡动画的方法不再讲述,这里直接实现动画过程。
参考动画效果
Today中的应用卡片,打开和关闭的效果。
实现动画效果
实现的效果也比较粗糙,有待改进,很多细节动画没有实现。
首先我们分析Present动画效果:
- 点击collectionView或者tableview的cell卡片。
- 卡片的大图逐渐放大形成卡片详情页的头图。
- 图片放大的过程中,详情页逐渐展示,右上角的按钮从透明到显现。
Dismisss过程是其反过程。
PushTranstionController
分析完动画过程,我们便可以开始实现动画。
import UIKit
class PushTranstionController: NSObject, UIViewControllerAnimatedTransitioning {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 1.0
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
guard let fromVC = transitionContext.viewController(forKey: .from) as? ViewController,
let toVC = transitionContext.viewController(forKey: .to) as? DetailViewController,
let selectedCell = fromVC.selectedCell else {
return
}
let containerView = transitionContext.containerView
let finalFrame = transitionContext.finalFrame(for: toVC)
let frame = selectedCell.convert(selectedCell.imageView.frame, to: fromVC.view)
toVC.view.frame = frame
toVC.view.layer.cornerRadius = 15
toVC.view.layer.masksToBounds = true
toVC.topImageView.frame.size.width = ScreenWidth - 60
toVC.topImageView.frame.size.height = 400
containerView.addSubview(toVC.view)
let duration = transitionDuration(using: transitionContext)
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0, options: [], animations:
{
toVC.view.frame = finalFrame
toVC.topImageView.frame.size.width = ScreenWidth
toVC.topImageView.frame.size.height = ScreenHeight * 0.55
toVC.closeBtn.alpha = 1
}) { (_) in
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
}
}
}
ViewController
为卡片控制器,DetailViewController
为卡片详情控制器。
注意:这里需要在卡片控制器设置selectedCell
关键属性,用于动画控制器获取被点击cell的frame
模型。
代码实现过程:
- 动画资源准备。获取
fromVC
、toVC
和fromVC.selectedCell
。获取过渡语境的containerView
,视图控制器的最终大小finalFrame
,点击cell
的imageView
在源视图的frame
(强调:这里的frame
不是cell
的imageView在cell
的frame
而是在源视图坐标系下的frame
)等。 - 动画初始化设置。将详情页的
frame
设置为卡片的frame
,设置圆角,设置头图的size
缩小为大图的size
。 - 创建动画。使用弹性动画,详情页
frame
更新(对应逐渐放大),头图size
还原,按钮实化。
PopTransitionController
pop动画为其反过程。这里贴出代码。
class PopTransitionController: NSObject, UIViewControllerAnimatedTransitioning {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.5
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
guard let fromVC = transitionContext.viewController(forKey: .from) as? DetailViewController,
let toVC = transitionContext.viewController(forKey: .to) as? ViewController,
let selectedCell = toVC.selectedCell else {
return
}
let containerView = transitionContext.containerView
containerView.insertSubview(toVC.view, at: 0)
let frame = selectedCell.convert(selectedCell.imageView.frame, to: toVC.view)
let duration = transitionDuration(using: transitionContext)
toVC.view.isHidden = true
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: [], animations:
{
fromVC.view.frame = frame
fromVC.view.layer.cornerRadius = 15
fromVC.view.layer.masksToBounds = true
fromVC.topImageView.frame.size.width = ScreenWidth - 60
fromVC.topImageView.frame.size.height = 400
fromVC.closeBtn.alpha = 0
}) { (_) in
toVC.view.isHidden = false
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
}
}
}