iOS-自定義轉(zhuǎn)場(chǎng)效果

  • 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
        }
        
    }
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容