NavigationControllerの画面遷移アニメーションの変更

# 概要
ナビゲーションコントローラーでの画面遷移アニメーションを変更する。
## 実装環境
Xcode 10.1
Swift 4.2.1

## コード

### 先ずは通常の画面遷移
```AppDelegate.swift
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var window: UIWindow?
    
    var navigationController: UINavigationController?
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        let viewController: ViewController = ViewController()
        //set viewController as rootViewController of navi
        navigationController = UINavigationController(rootViewController: viewController)
        //hide navigation bar
        navigationController?.setNavigationBarHidden(true, animated: false)
        //set window
        self.window = UIWindow(frame: UIScreen.main.bounds)
        self.window!.backgroundColor = .white
        //set navi as rootViewController
        self.window!.rootViewController = navigationController
        self.window!.makeKeyAndVisible()
        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
    }

    func applicationWillTerminate(_ application: UIApplication) {
    }
}
```

```ViewController.swift
import UIKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        createImage()
        createButton()
    }
    
    func createImage() {
        let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height))
        imageView.image = UIImage(named: "image1")
        imageView.contentMode = .scaleAspectFill
        self.view.addSubview(imageView)
    }
    
    func createButton(){
        let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
        button.center = self.view.center
        button.setTitle("next", for: .normal)
        button.backgroundColor = UIColor(red: 200/255, green: 200/255, blue: 200/255, alpha: 1.0)
        button.addTarget(self, action: #selector(onButtonTapped), for: .touchUpInside)
        self.view.addSubview(button)
    }
    
    @objc func onButtonTapped(){
        /* if you want to use default transitions, please uncomment out below. */
        //let transition = CATransition()
        //transition.duration = 0.5
        //transition.type = CATransitionType.fade
        //following types are used with subtype
        //transition.type = CATransitionType.moveIn
        //transition.type = CATransitionType.push
        //transition.type = CATransitionType.reveal
        //example of subtype
        //transition.subtype = CATransitionSubtype.fromBottom
        //navigationController?.view.layer.add(transition, forKey: nil)
        
        let view = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height))
        view.alpha = 0
        view.backgroundColor = .white
        self.view.addSubview(view)
        UIWindow.animate(withDuration: 1.0, animations: {
           view.alpha = 1.0
        }) { (Bool) in
            DispatchQueue.main.asyncAfter(deadline: .now()+0.2, execute: {
                //Attention "animated" is "false"
                self.navigationController?.pushViewController(nextViewController(), animated: false)
            })
            DispatchQueue.main.asyncAfter(deadline: .now()+1.0, execute: {
                view.removeFromSuperview()
            })
        }
    }
}
```

```nextViewController.swift
import UIKit

class nextViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        createImage()
        createButton()
    }
    
    func createImage() {
        let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height))
        imageView.image = UIImage(named: "image2")
        imageView.contentMode = .scaleAspectFill
        self.view.addSubview(imageView)
    }
    
    func createButton(){
        let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
        button.center = self.view.center
        button.setTitle("back", for: .normal)
        button.backgroundColor = UIColor(red: 200/255, green: 200/255, blue: 200/255, alpha: 1.0)
        button.addTarget(self, action: #selector(onButtonTapped), for: .touchUpInside)
        self.view.addSubview(button)
    }
    
    @objc func onButtonTapped(){
        let view = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height))
        view.alpha = 0
        view.backgroundColor = .white
        self.view.addSubview(view)
        UIWindow.animate(withDuration: 1.0, animations: {
            view.alpha = 1.0
        }) { (Bool) in
            DispatchQueue.main.asyncAfter(deadline: .now()+0.2, execute: {
                //Attention not pushViewController
                //popToViewController is back ViewController method
                self.navigationController?.popToViewController(self.navigationController!.viewControllers[0], animated: false)
            })
            DispatchQueue.main.asyncAfter(deadline: .now()+1.0, execute: {
                view.removeFromSuperview()
            })
        }
    }
}
```

## 結果
![ezgif.com-video-to-gif-10.gif](https://qiita-image-store.s3.amazonaws.com/0/328170/04aabde7-148c-0358-74f6-19392cbf4f56.gif)

## 解説
今回の実装ではstoryboardを使わなかったためstoryboardのファイルは削除している。
それなのでInfo.plistからstoryboard file base nameを削除しAppDelegateでwindowを設定した。

### 遷移アニメーションの変更部分
navigationControllerのanimatedをfalseにすることで横にスライドするアニメーションを行わないようにする。

```swift
self.navigationController?.pushViewController(nextViewController(), animated: false)
```

### その他のやり方
コメントアウトしているところを参考にしてもらえれば分かるようにnavigationControllerのtypeを変更することで遷移方法を変更できる。

segueのcross dissolveのようなanimationであればtypeをfadeにすることで簡単に実装できるだろう。

## 参考
[CATransition]
(https://developer.apple.com/documentation/quartzcore/catransition)
[How do I cross dissolve when pushing views on a UINavigationController in iOS 7?]
(https://stackoverflow.com/questions/23530538/how-do-i-cross-dissolve-when-pushing-views-on-a-uinavigationcontroller-in-ios-7)
[How do I create a new Swift project without using Storyboards?]
(https://stackoverflow.com/questions/24046898/how-do-i-create-a-new-swift-project-without-using-storyboards)