7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ZOZOテクノロジーズ #4Advent Calendar 2019

Day 18

WEARに投稿したコーディネート画像に雪を降らせて映えを狙う

Last updated at Posted at 2019-12-17

##はじめに
この記事は、ZOZOテクノロジーズ #4AdventCalendar2019の記事です。
昨日は@kurararararaさんのCharles for Macでレスポンスを変更する方法の記事でした。

ZOZOテクノロジーズでは、他にもAdventCalenderを書いている方がいらっしゃるので、よかったらみていってください。

##映えを狙う
今回私@koiwai2020は、WEARに投稿したこちらのコーディネート画像に雪を降らせて、映えを狙いたいと考えました。
ゆき.PNG

今回はCABasicAnimationを使ったアニメーションによって、雪が降らせてみることに挑戦しました。

早速ですがアニメーションを使用して、投稿画像に雪を降らせた完成形がこちらになります。

CABasicAnimationにはopacitybackgroundColorpositiontransform.scale.xなどのkey pathが用意されていて、これを指定してアニメーションを作ります。
今回雪が降る様子を作る為に、以下の2つの動きをCABasicAnimationを使って表現しました。

  • 雪の画像を移動させる。
  • 雪の画像を徐々に薄くする。

##画像を移動させるアニメーション
雪を降らせるにあたって、まず画像を移動させるアニメーションを作ります。
移動させるアニメーションは、positionをkey pathに設定して使います。

func fallAnimation() -> CABasicAnimation {
        let fallAnimation = CABasicAnimation(keyPath: "position")
        // 0から1までのランダムな係数を用意して、アニメーションの位置を調整するための値
        let random = CGFloat.random(in: 0 ..< 1)
        // アニメーション開始時の座標
        let fromPoint = CGPoint(x: UIScreen.main.bounds.width * random, y: 0)
        // アニメーション完了時の座標
        let toPoint = CGPoint(x: UIScreen.main.bounds.width * random, y: UIScreen.main.bounds.height)
        // アニメーション開始時の座標を設定
        fallAnimation.fromValue = fromPoint
        // アニメーション完了時の座標を設定
        fallAnimation.toValue = toPoint
        // アニメーションの速度を設定
        fallAnimation.duration = 1.5

        return fallAnimation
}

##画像を透過させるアニメーション
次に降る雪が地上に近くにつれて、溶けていく様子を画像を透過させるアニメーションを使って作ります。
透過のアニメーションは、opacityをkey pathに設定して使います。

func thawAnimation() -> CABasicAnimation {
        let thawAnimation = CABasicAnimation(keyPath: "opacity")
        // アニメーション開始時のalpha値
        thawAnimation.fromValue = 1.0
        // アニメーション終了時のalpha値
        thawAnimation.toValue = 0.0
        // アニメーションの速度を設定
        thawAnimation.duration = 1.5
        // アニメーション完了時の状態を保持
        thawAnimation.fillMode = .forwards

        return thawAnimation
}

##作ったアニメーションを画像に反映させる
作ったアニメーションを実際に、画像に反映させてみます。

アニメーションは、CALayeradd(_:forKey:)を呼び出したタイミングで開始されます。
その為、次のstartSnowAnimationが呼び出されたタイミングで雪の画像が徐々に薄くなりながら、落ちていきます。

画像にアニメーションを追加する処理
func startSnowAnimation() {
        view.addSubview(snowImageView)
        snowImageView.layer.add(fallAnimation(), forKey: "")
        snowImageView.layer.add(thawAnimation(), forKey: "")
}

##アニメーションを繰り返す
実際にstartAnimationを実行してみると、一粒の雪しか降ってきませんでした。
なので今回は、Timerを使用して一定の周期でアニメーションを開始するようにしました。

用意したTimer
let snowAnimationTimer = Timer.scheduledTimer(timeInterval: 0.2,
                                              target: self,
                                              selector: #selector(startSnowAnimation),
                                              userInfo: nil,
                                              repeats: true)

用意したTimerを、アニメーションを開始したい任意のタイミングで動かします。

Timerを動かす
override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        RunLoop.main.add(snowAnimationTimer, forMode: .common)
}

これで雪のアニメーションが繰り返し行われるので、自然な見た目になります。

##アニメーションが終ったら
アニメーションが終ったら、追加したアニメーションや画像の削除を行います。
アニメーションの完了には、CAAnimationDelegateにて用意されているanimationDidStop:finished:を使います。
animationDidStop:finished:を呼ぶ為には、最初に作ったアニメーションの設定処理に以下の設定を追加する必要があります。

  • アニメーションにdelegateを設定する。
  • isRemovedOnCompletionプロパティを無効にする。

isRemovedOnCompletionは、アニメーションが完了した際に削除するかどうかを決定します。
これが有効のままですと、animationDidStop:finished:は呼ばれずに、アニメーションのオブジェクトは削除されます。

透過させるアニメーションthawAnimationを例に設定を追加すると、次のようになります。

func thawAnimation() -> CABasicAnimation {
        let thawAnimation = CABasicAnimation(keyPath: "opacity")

        thawAnimation.delegate = self // CAAnimationDelegateの設定を追加

        thawAnimation.fromValue = 1.0
        thawAnimation.toValue = 0.0
        thawAnimation.duration = 1.5
        thawAnimation.fillMode = .forwards

        thawAnimation.isRemovedOnCompletion = false //isRemovedOnCompletionはデフォルトtrue

        return thawAnimation
}

設定が済んだら、animationDidStop:finished:内にアニメーション完了時の処理を追加します。
今回は、アニメーションが完了したタイミングで雪画像のImageViewごと削除しています。

func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        snowImageView.removeFromSuperview()
}

以上で、投稿したコーディネート画像を映えさせる?雪のアニメーションの実装ができました。

##さいごに
CABasicAnimationのfromValuetoValuedurationを調整することでアニメーションの印象が変わりました。
普段慣れ親しんでいる雪であっても、実際に表現するとなると難しいのだなと感じました。

明日は、@Kyou13さんです。

読んで下さった皆さま、ありがとうございました🙇‍♂️🏂🙇‍♂️

7
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?