[iOS] Twitterのようなアプリ起動アニメーション【動作イメージ追加】

  • 132
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

Twitter公式アプリの起動時と似たアニメーションをSwiftで実装したので紹介します。
GitHub : https://github.com/okmr-d/App-Launching-like-Twitter

動作イメージ

animation.gifanimation2.gif

やり方

①ロゴ画像を用意
②Launch Screenを設定
③Launch Screenと同じ見た目になるよう初期表示されるviewを設定(←ここがミソ)
④アニメーションさせる

①ロゴ画像を用意

起動画面(Launch ScreenとかSplashとも呼ぶらしい)に初期表示するロゴ画像を透過PNGで用意します。
画面サイズより大きく拡大するので、大きめの画像がいいです。今回は1000px × 1000pxにしています。
logo.gif

②Launch Screenを設定

LaunchScreen.xibのviewの背景に好きな色を指定し、ロゴ画像をviewの中心に配置します。
LaunchScreen.gif

③Launch Screenと同じ見た目になるよう初期表示されるviewを設定

AppDelegate.swiftのapplication(_:didFinishLaunchingWithOptions:)メソッドにて、初期表示されるviewをLaunch Screenと同じ見た目になるように設定します。
※今回の一番のポイントは「3.」でviewをロゴ画像の形にマスクする点です。

  • 1. windowの背景色にLaunchScreen.xibのviewの背景色と同じ色を設定
  • 2. rootViewControllerをStoryBoardから設定 (今回はUINavigationControllerとしているが、他のViewControllerでも可)
  • 3. rootViewController.viewをロゴ画像の形にマスクし、LaunchScreen.xibのロゴ画像と同サイズ・同位置に配置
  • 4. rootViewController.viewの最前面に白いviewを配置
AppDelegate.swift
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

        // ▼ 1. windowの背景色にLaunchScreen.xibのviewの背景色と同じ色を設定
        self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
        self.window!.backgroundColor = UIColor(red: 241/255, green: 196/255, blue: 15/255, alpha: 1)
        self.window!.makeKeyAndVisible()

        // ▼ 2. rootViewControllerをStoryBoardから設定 (今回はUINavigationControllerとしているが、他のViewControllerでも可)
        let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
        var navigationController = mainStoryboard.instantiateViewControllerWithIdentifier("navigationController") as! UIViewController
        self.window!.rootViewController = navigationController

        // ▼ 3. rootViewController.viewをロゴ画像の形にマスクし、LaunchScreen.xibのロゴ画像と同サイズ・同位置に配置
        navigationController.view.layer.mask = CALayer()
        navigationController.view.layer.mask.contents = UIImage(named: "logo.png")!.CGImage
        navigationController.view.layer.mask.bounds = CGRect(x: 0, y: 0, width: 60, height: 60)
        navigationController.view.layer.mask.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        navigationController.view.layer.mask.position = CGPoint(x: navigationController.view.frame.width / 2, y: navigationController.view.frame.height / 2)

        // ▼ 4. rootViewController.viewの最前面に白いviewを配置
        var maskBgView = UIView(frame: navigationController.view.frame)
        maskBgView.backgroundColor = UIColor.whiteColor()
        navigationController.view.addSubview(maskBgView)
        navigationController.view.bringSubviewToFront(maskBgView)

        // 中略 (「④アニメーションさせる」を参照)

        return
    }

ここまでの実装で、LaunchScreenの表示終了後もLaunchScreenと全く同じ画面に見えるようになります。

④アニメーションさせる

続けて③で設定したviewにアニメーションを設定します。

  • 5. rootViewController.viewのマスクを少し縮小してから、画面サイズよりも大きくなるよう拡大するアニメーション
  • 6. rootViewController.viewの最前面に配置した白いviewを透化するアニメーション (完了後に親viewから削除)
  • 7. rootViewController.viewを少し拡大して元に戻すアニメーション
  • 8. 「5.」のアニメーション完了時のdelegateメソッドを実装し、マスクを削除する
AppDelegate.swift
    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

        // 中略 (「③LaunchScreenと同じ見た目になるよう初期表示のviewを設定」を参照)

        // ▼ 5. rootViewController.viewのマスクを少し縮小してから、画面サイズよりも大きくなるよう拡大するアニメーション
        let transformAnimation = CAKeyframeAnimation(keyPath: "bounds")
        transformAnimation.delegate = self
        transformAnimation.duration = 1
        transformAnimation.beginTime = CACurrentMediaTime() + 1 // 開始タイミングを1秒遅らせる
        let initalBounds = NSValue(CGRect: navigationController.view.layer.mask.bounds)
        let secondBounds = NSValue(CGRect: CGRect(x: 0, y: 0, width: 50, height: 50))
        let finalBounds = NSValue(CGRect: CGRect(x: 0, y: 0, width: 2000, height: 2000))
        transformAnimation.values = [initalBounds, secondBounds, finalBounds]
        transformAnimation.keyTimes = [0, 0.5, 1]
        transformAnimation.timingFunctions = [CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut), CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)]
        transformAnimation.removedOnCompletion = false
        transformAnimation.fillMode = kCAFillModeForwards
        navigationController.view.layer.mask.addAnimation(transformAnimation, forKey: "maskAnimation")

        // ▼ 6. rootViewController.viewの最前面に配置した白いviewを透化するアニメーション (完了後に親viewから削除)
        UIView.animateWithDuration(0.1,
            delay: 1.35,
            options: UIViewAnimationOptions.CurveEaseIn,
            animations: {
                maskBgView.alpha = 0.0
            },
            completion: { finished in
                maskBgView.removeFromSuperview()
        })

        // ▼ 7. rootViewController.viewを少し拡大して元に戻すアニメーション
        UIView.animateWithDuration(0.25,
            delay: 1.3,
            options: UIViewAnimationOptions.TransitionNone,
            animations: {
                self.window!.rootViewController!.view.transform = CGAffineTransformMakeScale(1.05, 1.05)
            },
            completion: { finished in
                UIView.animateWithDuration(0.3,
                    delay: 0.0,
                    options: UIViewAnimationOptions.CurveEaseInOut,
                    animations: {
                        self.window!.rootViewController!.view.transform = CGAffineTransformIdentity
                    },
                    completion: nil
                )
        })

        return true
    }

    // ▼ 8. 「5.」のアニメーション完了時のdelegateメソッドを実装し、マスクを削除する
    override func animationDidStop(anim: CAAnimation!, finished flag: Bool) {
        // remove mask when animation completes
        self.window!.rootViewController!.view.layer.mask = nil
    }

これで完成!
変なところあったら指摘ください。

GitHub : https://github.com/okmr-d/App-Launching-like-Twitter