Custom Transition


前の記事からPresentationControllerとは何かを学びました.しかし、Transition Animatorを提供する部分でUIViewControllerAnimatedTransitioningという友人を見た.今日のテーマはこいつだ.

UIViewControllerAnimatedTransitioning


これは、Custom Transitionに必要なアニメーションを実現するために集約されたプロトコルです.このプロトコルを採用した実装体を渡せばよい.
このプロトコルでは、[一定時間内にアニメーションを定義してVCを画面外に切り替えるオブジェクト]を作成できます.会話型の場合はUIViewControllerInteractiveTransitioningで処理すべきです.実現する方法は次のとおりです.
  • transitionDuration(using:) : Required
  • Transition AnimationのDurationを指定します.
  • animateTransition(using:) : Required
  • アニメーションを定義します.
  • の状況を満たすために、複数の異なるanimatorを提供することもできる.(例えば、.present.dismiss)
  • .
    両方の方法は、UIViewControllerContextTransitioningというプロトコルインプリメンテーションからTransitionの発生期間の情報を得ることができる.これをTransition Contextと呼びます.ここには、上述したcontainerViewFrameの情報、isInteractiveisAnimated等が含まれる.

    Project


    前に見たAppStoreの延長線から知っておきましょう.従来はCardDetailViewControllerUIViewControllerTransitioningDelegateを採用していたが、ここでは3つの方法が実現され、表示コントローラとは無関係の2つの方法がある.
    extension CardDetailViewController: UIViewControllerTransitioningDelegate {
        
        func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return TodayAnimationTransition(animationType: .present)
        }
        
        func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return TodayAnimationTransition(animationType: .dismiss)
        }
        
        func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
            return CardPresentationController(presentedViewController: presented, presenting: presenting)
        }
    }
    上の2つの方法はそれです.前の記事ではpresentとdiskに適したanimatorを提供した.今はあいつの正体を確認しなければならない.

    TodayAnimationTransition

    fileprivate let transitonDuration: TimeInterval = 1.0
    
    enum AnimationType {
        case present
        case dismiss
    }
    
    class TodayAnimationTransition: NSObject {
        let animationType: AnimationType!
        
        init(animationType: AnimationType) {
            self.animationType = animationType
            super.init()
        }
    }
    まず基本料理を見てみましょうanimatorに関連するものを扱うために,時間間隔を定義し,タイプ別に管理した.初期化時にTypeが定義されている場合は、対応するAnimatorを指定したい場合があります.
    extension TodayAnimationTransition: UIViewControllerAnimatedTransitioning {
    
        func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            return transitonDuration
        }
        
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            if animationType == .present {
                animationForPresent(using: transitionContext)
            } else {
                animationForDismiss(using: transitionContext)
            }
        }
    
    }
    先ほど述べたUIViewControllerAnimatedTransitioningを実現するために必要な2つの方法.アニメーションの持続時間とどのようなアニメーションを行うかについての方法です.コードライターはtypeに従って2つの処理を行う.
    extension TodayAnimationTransition: UIViewControllerAnimatedTransitioning {
    
        func animationForPresent(using transitionContext: UIViewControllerContextTransitioning) {
            let containerView = transitionContext.containerView
            //1.Get fromVC and toVC
            guard let fromVC = transitionContext.viewController(forKey: .from) as? UITabBarController else { return }
            guard let tableViewController = fromVC.viewControllers?.first as? TodayViewController else { return }
            guard let toVC = transitionContext.viewController(forKey: .to) as? CardDetailViewController else { return }
            guard let selectedCell = tableViewController.selectedCell else { return }
            
            let frame = selectedCell.convert(selectedCell.bgBackView.frame, to: fromVC.view)        
            //2.Set presentation original size.
            toVC.view.frame = frame
            toVC.scrollView.imageView.frame.size.width = GlobalConstants.todayCardSize.width
            toVC.scrollView.imageView.frame.size.height = GlobalConstants.todayCardSize.height
            
            containerView.addSubview(toVC.view)
            
            //3.Change original size to final size with animation.
            UIView.animate(withDuration: transitonDuration, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0, options: [], animations: {
                toVC.view.frame = UIScreen.main.bounds
                toVC.scrollView.imageView.frame.size.width = kScreenW
                toVC.scrollView.imageView.frame.size.height = GlobalConstants.cardDetailTopImageH
                toVC.closeBtn.alpha = 1
                
                fromVC.tabBar.frame.origin.y = kScreenH
            }) { (completed) in
                transitionContext.completeTransition(completed)
            }
        }
        
        func animationForDismiss(using transitionContext: UIViewControllerContextTransitioning) {
            guard let fromVC = transitionContext.viewController(forKey: .from) as? CardDetailViewController else { return }
            guard let toVC = transitionContext.viewController(forKey: .to) as? UITabBarController else { return }
            guard let tableViewController = toVC.viewControllers?.first as? TodayViewController else { return }
            guard let selectedCell = tableViewController.selectedCell else { return }
            
            UIView.animate(withDuration: transitonDuration - 0.3, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: [], animations: {
                let frame = selectedCell.convert(selectedCell.bgBackView.frame, to: toVC.view)
                fromVC.view.frame = frame
                fromVC.view.layer.cornerRadius = GlobalConstants.toDayCardCornerRadius
                fromVC.scrollView.imageView.frame.size.width = GlobalConstants.todayCardSize.width
                fromVC.scrollView.imageView.frame.size.height = GlobalConstants.todayCardSize.height
                fromVC.closeBtn.alpha = 0
                
                toVC.tabBar.frame.origin.y = kScreenH - toVC.tabBar.frame.height
            }) { (completed) in
                transitionContext.completeTransition(completed)
                toVC.view.addSubview(toVC.tabBar)
            }
        }
        
    }
    実際に行われたコードはここに含まれています.実際,この部分は今後の実装で挿入されるため,判断はあまり重要ではなくスキップされる.

    の最後の部分


    こうしてCustomTransitionのコンセプトがわかりました!インタラクションが必要な場合は、他の人のYouTubeリンクが含まれます.万一知らなかったら、その時になってからついて行きましょう.終わりだ!

    Reference

  • UIViewControllerAnimatedTransitioning
  • UIViewControllerInteractiveTransitioning
  • UIViewControllerContextTransitioning
  • iOS)UIレンダリングコントローラ、App Storeクローンアプリケーションについて
  • iOS)プレゼンテーション、Transition、Animation...
  • iOS Swift Tutorial: Create Advanced Interactive Animations with UIKit
  • appstore-clone