- Swift5.3
-
效果图
效果图.gif
控制器从A——>B
在两个控制器里设置navigation的代理
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.delegate = self
}
在A控制器里实现下面的方法
//MARK: Navigation Delegate
extension A控制器:UINavigationControllerDelegate,UIViewControllerAnimatedTransitioning{
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 1.0
}
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning?{
return self
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
//先拿到前后两个viewcontroller 以及 实现动画的容器
let toVC = transitionContext.viewController(forKey: .to)! as! B控制器
let containerView = transitionContext.containerView
//对Cell上的 imageView 截图,同时将这个 imageView 本身隐藏
let cell = collectionView.cellForItem(at: selectIndexPath!) as! A控制器的cell
let snapshotView = UIImageView(image: cell.imageView!.image)
snapshotView.contentMode = .scaleAspectFit
// 坐标转换 将cell.iconImgV的rect从其父view中转换到containerView视图中,返回在containerView视图中的rect
snapshotView.frame = containerView.convert((cell.imageView.frame), from: cell.imageView.superview)
cell.imageView.isHidden = true
//设置第二个 viewController ,将它的放到过渡后的位置,但让他完全透明,我们会在过渡时给它一个淡入的效果。
toVC.view.frame = transitionContext.finalFrame(for: toVC)
toVC.view.alpha = 0
toVC.imageView.isHidden = true
//把动画前后的两个ViewController加到容器中,顺序很重要,snapShotView在上方
containerView.addSubview(toVC.view)
containerView.addSubview(snapshotView)
UIView.animate(withDuration: self.transitionDuration(using: transitionContext), delay: 0.0, usingSpringWithDamping: 0.6, initialSpringVelocity: 1.0, options: .curveLinear, animations: {
//将截图放到第二个viewController的imageView上
snapshotView.frame = containerView.convert(toVC.imageView.frame, from: toVC.imageView.superview)
toVC.view.alpha = 1.0
}) { (finished) in
snapshotView.removeFromSuperview()
cell.imageView.isHidden = false
toVC.imageView.isHidden = false
//告诉系统动画结束
transitionContext.completeTransition(true)
}
}
}
控制器从B——>A
在B控制器里实现下面的方法
//MARK: Navigation Delegate
extension B控制器:UINavigationControllerDelegate,UIViewControllerAnimatedTransitioning{
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.25
}
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning?{
return self
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let vc = transitionContext.viewController(forKey: .to)
//实现过渡的控制器 和 容器view
let toVC = vc as! A控制器
let fromVC = transitionContext.viewController(forKey: .from) as! B控制器的cell
let containerView = transitionContext.containerView
//前一个VC设置 截图
let snapShotView = UIImageView(image: fromVC.imageView.image)
snapShotView.contentMode = .scaleAspectFit
snapShotView.frame = containerView.convert(fromVC.imageView.frame, from: fromVC.view)
fromVC.imageView.isHidden = true
//下一个VC设置
toVC.view.frame = transitionContext.finalFrame(for: toVC)
let cell = toVC.collectionView.cellForItem(at: selectIndexPath!) as! HomeCollectionViewCell
cell.imageView.isHidden = true
// 添加到容器
containerView.insertSubview(toVC.view, belowSubview: fromVC.view)
containerView.addSubview(snapShotView)
UIView.animate(withDuration: self.transitionDuration(using: transitionContext), animations: {
containerView.layoutIfNeeded()
fromVC.view.alpha = 0
snapShotView.frame = containerView.convert((cell.imageView.frame), from: cell.imageView.superview)
}) { (finished) in
// 告诉系统动画结束
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
if transitionContext.transitionWasCancelled {
//手势取消了,原来隐藏的imageView要显示出来
fromVC.imageView.isHidden = false
}else {
//手势成功,cell的imageView也要显示出来
cell.imageView.isHidden = false
}
//动画交互动作完成或取消后,移除临时动画文件
snapShotView.removeFromSuperview()
}
}
自定义右划返回上一页面的手势动画,在B控制器里实现下面的方法
var transitionInteractive: HomeTransitionInteractive!
override func viewDidLoad() {
super.viewDidLoad()
let interactive = HomeTransitionInteractive()
interactive.addPanGestureForViewController(viewController: self)
transitionInteractive = interactive
}
//MARK: Navigation Delegate
extension HomeCellDetailsViewController:UINavigationControllerDelegate,UIViewControllerAnimatedTransitioning{
func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
//手势开始的时候才需要传入手势过渡代理,如果直接pop或push,应该返回nil,否者无法正常完成pop/push动作
return self.transitionInteractive.isInteractive == true ? self.transitionInteractive : nil
}
}
自定义手势动画HomeTransitionInteractive
//
// HomeTransitionInteractive.swift
// PhotoCalendar
//
// Created by Shi Jiachen on 2021/02/18.
//
import UIKit
class HomeTransitionInteractive: UIPercentDrivenInteractiveTransition {
var viewController: UIViewController!
var isInteractive: Bool!
func addPanGestureForViewController(viewController : UIViewController) {
let pan = UIPanGestureRecognizer(target: self, action: #selector(self.handleGesture(panGesture: )))
self.viewController = viewController
viewController.view.addGestureRecognizer(pan)
}
@objc func handleGesture(panGesture:UIPanGestureRecognizer) {
let translation = panGesture.translation(in: panGesture.view)
var percentComplete:CGFloat = 0.0
//左右滑动的百分比
percentComplete = translation.x / SCREEN_WIDTH
percentComplete = abs(percentComplete)
// print(percentComplete)
switch panGesture.state {
case .began:
self.isInteractive = true
self.viewController.navigationController?.popViewController(animated: true)
case .changed:
//手势过程中,通过updateInteractiveTransition设置转场过程动画进行的百分比,然后系统会根据百分比自动布局动画控件,不用我们控制了
self.update(percentComplete)
case .ended:
self.isInteractive = false
//手势完成后结束标记并且判断移动距离是否过半,过则finishInteractiveTransition完成转场操作,否者取消转场操作,转场失败
if percentComplete > 0.35 {
self.finish()
}else {
self.cancel()
}
default:
break
}
}
}
网友评论