post Image
iOS標準の写真アプリのように画像をズームしながら遷移させる

次のようなiOS標準の写真アプリのように画像をズームする遷移を実装しました。

最初は「よくある遷移だし簡単に実装できるでしょ〜(ヘラヘラ)」って始めたら結構苦労したので、同じような人の手助けになればと思います。(終わってみれば大したことなかった気もする)

正直、こちらを参考にすればそれっぽいものが作れますが、二箇所ほど詰まった点があるので、そちらを解説していきます。
(UIViewControllerAnimatedTransitioningについてわからない場合はこちらを参考にすると良いと思います)

githubにサンプルを用意したのでそちらもよかったら参考にしてください。

詰まった点

目的のUIViewControllerが取得できない

func animateTransition(using transitionContext: UIViewControllerContextTransitioning)内で、遷移元と遷移先のViewControllerを取得する際の

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
        let toVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!

         //以下アニメーションの処理       
}

の処理で詰まりました。どう詰まったかというと、UINavigationControllerやUITabbarControllerを使っている場合はそちらが取得されてしまい、遷移の際に必要なUIImageViewを取得できません。
ですので、今回は

protocol TransitionProtocol {
    func transitionImageView() -> UIImageView //コピーのUIImageViewを返すメソッド
    func trnasitionImageView(isHidden: Bool) //アニメーションの前後でUIImageViewの表示を操作するメソッド
}

というプロトコルを用意し、遷移元と遷移先のViewControllerに適用しました。そして、アニメーションの処理を実装しているクラスに次のようなメソッドを実装し、UIImageViewを取得する際には、このメソッドで得られるTransitionProtocolを経由して、取得するようにしました。

 private func getTransitionProtocol(viewController: UIViewController?) -> TransitionProtocol? {
        guard var viewController = viewController else { return nil }

        while (viewController as? TransitionProtocol) == nil {
            if let tab = viewController as? UITabBarController {
                viewController = tab.selectedViewController!
            } else if let navi = viewController as? UINavigationController {
                let viewControllers = navi.childViewControllers
                viewController = navi.childViewControllers[viewControllers.count - 1]
            } else {
                return nil
            }
        }
        return viewController as? TransitionProtocol
    }

contentModeの切り替え

しかし、このままだとアニメーションの前後で画像が少しカクッとしてしまいます。
これの原因としてはUIImageViewのframeがそのままであるにも関わらず、アニメーションの前後でcontentModeが切り替わってしまうためです。
そのため、今回は解決策としてUImageViewに表示しているUIImageの大きさを取得できるようUIImageViewをextensionし、画像の大きさを変えることなくcontentModeを切り替えます。

import UIKit
import AVFoundation

extension UIImageView {

    var imageSize: CGSize? {
        guard let image = image else { return nil }

        return AVMakeRect(aspectRatio: image.size, insideRect: bounds).size
    }
}
//contentModeを切り替える前後
let center = imageView.center
imageView.frame.size = imageView.imageSize!
imageView.center = center

アニメーションの前後などのcontentModeを切り替えるタイミングで上のようにしてやれば、contentModeを変更しても現在表示している状態と変わることはないと思います。
ただし、上のコードは一例でありpresentの時とdismissの時で変わったりもしますので、詳しくはサンプルのコードを見てください。

さいごに…

何気にQiitaで記事やコードを公開したりするのが初めてだったりします。
普段は独りで開発する機会がほとんどですので、もし「こう書くともっと記事が分かりやすくなる」や「ここのコードはこうするよりもこうした方がいい」などありましたら、アドバイスして頂けますと幸いです。


『 Swift 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。