- Swift5.3
-
效果圖
效果圖.gif
控制器從A——>B
在兩個(gè)控制器里設(shè)置navigation的代理
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.delegate = self
}
在A控制器里實(shí)現(xiàn)下面的方法
//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) {
//先拿到前后兩個(gè)viewcontroller 以及 實(shí)現(xiàn)動(dòng)畫(huà)的容器
let toVC = transitionContext.viewController(forKey: .to)! as! B控制器
let containerView = transitionContext.containerView
//對(duì)Cell上的 imageView 截圖,同時(shí)將這個(gè) imageView 本身隱藏
let cell = collectionView.cellForItem(at: selectIndexPath!) as! A控制器的cell
let snapshotView = UIImageView(image: cell.imageView!.image)
snapshotView.contentMode = .scaleAspectFit
// 坐標(biāo)轉(zhuǎn)換 將cell.iconImgV的rect從其父view中轉(zhuǎn)換到containerView視圖中,返回在containerView視圖中的rect
snapshotView.frame = containerView.convert((cell.imageView.frame), from: cell.imageView.superview)
cell.imageView.isHidden = true
//設(shè)置第二個(gè) viewController ,將它的放到過(guò)渡后的位置,但讓他完全透明,我們會(huì)在過(guò)渡時(shí)給它一個(gè)淡入的效果。
toVC.view.frame = transitionContext.finalFrame(for: toVC)
toVC.view.alpha = 0
toVC.imageView.isHidden = true
//把動(dòng)畫(huà)前后的兩個(gè)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: {
//將截圖放到第二個(gè)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
//告訴系統(tǒng)動(dòng)畫(huà)結(jié)束
transitionContext.completeTransition(true)
}
}
}
控制器從B——>A
在B控制器里實(shí)現(xiàn)下面的方法
//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)
//實(shí)現(xiàn)過(guò)渡的控制器 和 容器view
let toVC = vc as! A控制器
let fromVC = transitionContext.viewController(forKey: .from) as! B控制器的cell
let containerView = transitionContext.containerView
//前一個(gè)VC設(shè)置 截圖
let snapShotView = UIImageView(image: fromVC.imageView.image)
snapShotView.contentMode = .scaleAspectFit
snapShotView.frame = containerView.convert(fromVC.imageView.frame, from: fromVC.view)
fromVC.imageView.isHidden = true
//下一個(gè)VC設(shè)置
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
// 告訴系統(tǒng)動(dòng)畫(huà)結(jié)束
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
if transitionContext.transitionWasCancelled {
//手勢(shì)取消了,原來(lái)隱藏的imageView要顯示出來(lái)
fromVC.imageView.isHidden = false
}else {
//手勢(shì)成功,cell的imageView也要顯示出來(lái)
cell.imageView.isHidden = false
}
//動(dòng)畫(huà)交互動(dòng)作完成或取消后,移除臨時(shí)動(dòng)畫(huà)文件
snapShotView.removeFromSuperview()
}
}
自定義右劃返回上一頁(yè)面的手勢(shì)動(dòng)畫(huà),在B控制器里實(shí)現(xiàn)下面的方法
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? {
//手勢(shì)開(kāi)始的時(shí)候才需要傳入手勢(shì)過(guò)渡代理,如果直接pop或push,應(yīng)該返回nil,否者無(wú)法正常完成pop/push動(dòng)作
return self.transitionInteractive.isInteractive == true ? self.transitionInteractive : nil
}
}
自定義手勢(shì)動(dòng)畫(huà)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
//左右滑動(dòng)的百分比
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:
//手勢(shì)過(guò)程中,通過(guò)updateInteractiveTransition設(shè)置轉(zhuǎn)場(chǎng)過(guò)程動(dòng)畫(huà)進(jìn)行的百分比,然后系統(tǒng)會(huì)根據(jù)百分比自動(dòng)布局動(dòng)畫(huà)控件,不用我們控制了
self.update(percentComplete)
case .ended:
self.isInteractive = false
//手勢(shì)完成后結(jié)束標(biāo)記并且判斷移動(dòng)距離是否過(guò)半,過(guò)則finishInteractiveTransition完成轉(zhuǎn)場(chǎng)操作,否者取消轉(zhuǎn)場(chǎng)操作,轉(zhuǎn)場(chǎng)失敗
if percentComplete > 0.35 {
self.finish()
}else {
self.cancel()
}
default:
break
}
}
}
