[iOS][Swift3.0] スターウォーズっぽいトランジションを入れるStarWars.iOS

ios_ui

今回は個人的に名前が気になったStarWars.iOSというOSSを試してみました。StarWars.iOSはViewControllerが崩れる感じのトランジションを入れることができます。下記はコンセプトページのGIF画像です。

コンセプトページ Star Wars App concept

画面を閉じる時に画面が粉々になるアニメーションが該当する箇所です。ライセンスはMITです。

Yalantis/StarWars.iOS

検証環境

今回は下記環境で試しています。

Xcode 8.2
Swift 3.0.2
CocoaPods 1.0.0

準備

導入

CocoaPodsで追加します。

use_frameworks!
target "ターゲット名"
    pod 'StarWars'
end

post_install do |installer|
    installer.pods_project.targets.each do |target|
        target.build_configurations.each do |configuration|
            configuration.build_settings['SWIFT_VERSION'] = "3.0"
        end
    end
end

実装

遷移の作成

まずは単純な画面遷移を作成します。今回はFirstViewControllerとSecondViewControllerを用意し、FirstViewControllerのOPENボタンを押すとモーダル(Present Modally Segue)でSecondViewControllerが表示されるようにしました。

Storyboard_Sample

また、アニメーションがわかりやすいように、背景色やコンポーネントを適宜配置しています。

トランジションを入れる

StarWars.iOSのトランジションはStarWarsGLAnimator()というクラスで用意されています。
StarWarsGLAnimatorはUIViewControllerAnimatedTransitioningプロトコルを適用したクラスになっているので、通常の画面遷移のトランジションを入れる時と同じように使うことができます。

モーダルで起動したSecondViewControllerの方のクラスにトランジションを変更するコードを入れます。処理自体は簡単で、ハイライトになった箇所がトランジションの変更として追加した処理です。

import UIKit
import StarWars

class SecondViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        transitioningDelegate = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    @IBAction func didTapClose(_ sender: Any) {
        dismiss(animated: true)
    }
}

extension SecondViewController: UIViewControllerTransitioningDelegate {
    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return StarWarsGLAnimator()
    }
}
実行結果

sample 1

エフェクトを変更する

UIViewControllerTransitioningDelegateのanimationController(forDismissed:)でそのままStarWarsGLAnimator()を返してますが、このプロパティを変えることによりアニメーションを変更させることができます。

extension SecondViewController: UIViewControllerTransitioningDelegate {
    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        let animator = StarWarsGLAnimator()
        animator.duration = 1
        animator.spriteWidth = 24

        return animator
    }
}

デフォルトではアニメーション時間(duration)は、破片?のサイズ(spriteWidth)はです。

実行結果

sample2

さいごに

(実際に使うには)使いどころは難しそうですが、面白いエフェクトだと思いました。
製作者のブログを見ると、このエフェクトを実現するために、UIDynamics、UIKit、Open GLのそれぞれで試しており、それぞれのベンチマークが載っていてとても興味深いです。

参考

UIDynamics, UIKit or OpenGL? 3 Types of iOS Animations for the Star Wars