最近 产品要iOS 使用 Google那套 Material Design ,所以 就研究实现相关的 动画逻辑,具体 什么设计咱不谈了。
说说需求吧:两个控制器之间需要有一些连接,比如,卡片 飞入。卡片是A,B的共同元素。
然后 就用Swift写了一个,OC版的 已经有大神写了,我在下面的连接 有跳转。
先看效果吧:
主要实现就是 实现了 分别为push 和 pop 实现了 UIViewControllerAnimatedTransitioning 协议,并在相关方法中完成动画设计。
1、push动画
//
// JYMagicMoveTransion.swift
// JYMagicMove
//
// Created by 杨勇 on 16/8/16.
// Copyright © 2016年 JackYang. All rights reserved.
//
import UIKit
class JYMagicMoveTransion: NSObject ,UIViewControllerAnimatedTransitioning{
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return 0.5;
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
//拿到 fromVC 和 toVC 以及 容器
let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) as! ViewController
let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) as! JYDetailController
let container = transitionContext.containerView();
//拿到 cell上的 imageView的快照 隐藏 cell上的imageView
let snapshotView = fromVC.selectCell.imageView.snapshotViewAfterScreenUpdates(false)
//设置快照的frame
snapshotView.frame = container!.convertRect(fromVC.selectCell.imageView.frame, fromView: fromVC.selectCell.imageView.superview)
//隐藏
fromVC.selectCell.imageView.hidden = true
//设置toVC 的位置 并设置为透明
toVC.view.frame = transitionContext.finalFrameForViewController(toVC)
toVC.view.alpha = 0
toVC.avaterImageView.hidden = true
//把 toVC的 view 和 快照 加到 容器 上,顺序!
container?.addSubview(toVC.view)
container?.addSubview(snapshotView)
//做动画前先把avaterImageView 的frame 更新一下 不然 storyboard 尺寸没有更新
toVC.avaterImageView.layoutIfNeeded()
UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
() -> Void in
//动画
snapshotView.frame = toVC.avaterImageView.frame
toVC.view.alpha = 1
}) { (finish:Bool) -> Void in
fromVC.selectCell.imageView.hidden = false // 把之前隐藏的 显示出来
toVC.avaterImageView.hidden = false
snapshotView.removeFromSuperview()
transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
}
}
}
2、pop动画(注释较少,主要是和push基本逻辑相等。)
//
// JYMagicPopTransion.swift
// JYMagicMove
//
// Created by 杨勇 on 16/8/16.
// Copyright © 2016年 JackYang. All rights reserved.
//
import UIKit
class JYMagicPopTransion: NSObject ,UIViewControllerAnimatedTransitioning{
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return 0.5
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
//拿到 fromVC 和 toVC 以及 容器
let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) as! JYDetailController
let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) as! ViewController
let container = transitionContext.containerView()
//拿到快照
let snapshotView = fromVC.avaterImageView.snapshotViewAfterScreenUpdates(false)
snapshotView.frame = container!.convertRect(fromVC.avaterImageView.frame, fromView: fromVC.avaterImageView.superview)
fromVC.avaterImageView.hidden = true
toVC.view.frame = transitionContext.finalFrameForViewController(toVC)
toVC.selectCell.imageView.hidden = true
container?.insertSubview(toVC.view, belowSubview: fromVC.view)
container?.addSubview(snapshotView)
UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
() -> Void in
snapshotView.frame = container!.convertRect(toVC.selectCell.imageView.frame, fromView: toVC.selectCell.imageView.superview)
fromVC.view.alpha = 0
}) { (finish: Bool) -> Void in
toVC.selectCell.imageView.hidden = false
snapshotView.removeFromSuperview()
fromVC.avaterImageView.hidden = false
transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
}
}
}
3、第三点就是滑动 的进度 我通过UIPercentDrivenInteractiveTransition实现。并且 给 第二个控制器加一个 手势(UIScreenEdgePanGestureRecognizer)
//
// JYDetailController.swift
// JYMagicMove
//
// Created by 杨勇 on 16/8/16.
// Copyright © 2016年 JackYang. All rights reserved.
//
import UIKit
class JYDetailController: UIViewController ,UINavigationControllerDelegate{
@IBOutlet weak var avaterImageView: UIImageView!
private var percentDrivenTransition :UIPercentDrivenInteractiveTransition?
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.delegate = self
let edgePan = UIScreenEdgePanGestureRecognizer.init(target: self, action:Selector("edgePanGesture:"))
edgePan.edges = UIRectEdge.Left
self.view.addGestureRecognizer(edgePan)
}
func edgePanGesture(edgePan:UIScreenEdgePanGestureRecognizer){
let progress = edgePan.translationInView(self.view).x / self.view.bounds.width
if edgePan.state == UIGestureRecognizerState.Began {
self.percentDrivenTransition = UIPercentDrivenInteractiveTransition()
self.navigationController?.popViewControllerAnimated(true)
} else if edgePan.state == UIGestureRecognizerState.Changed {
self.percentDrivenTransition?.updateInteractiveTransition(progress)
} else if edgePan.state == UIGestureRecognizerState.Cancelled || edgePan.state == UIGestureRecognizerState.Ended {
if progress > 0.5 {
self.percentDrivenTransition?.finishInteractiveTransition()
} else {
self.percentDrivenTransition?.cancelInteractiveTransition()
}
self.percentDrivenTransition = nil
}
}
func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
if operation == UINavigationControllerOperation.Pop {
return JYMagicPopTransion()
} else {
return nil
}
}
func navigationController(navigationController: UINavigationController, interactionControllerForAnimationController animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
if animationController is JYMagicPopTransion {
return self.percentDrivenTransition
} else {
return nil
}
}
}
可以看到,不断更新 progress,然后把percentDrivenTransition 通过 navigation的代理告诉它,完成动画更新。
OC版 是 KittenYang写的,我参考他的。原文有下载地址。