Viewの遷移時にアニメーションする

はじめに

アプリの起動時に初期Viewの切り替えをしたいことってあると思います。
例えば、初めて利用するときにユーザの名前を登録してもらうためのViewを表示し、2回目以降はそのViewを省略するケースなど。

その切り替えにはいわゆるフラグを使う方法でどのViewをレンダリングするかで対応できます。今回はその切り替えの仕組みではなく、切り替えの見栄えについてのお話です。

切り替えでアニメーションをする

そうです。アニメーションです。

Viewの遷移時にアニメーションを行わなければフラグが切り替わった瞬間にペッとViewが切り替わります。とても味気ない。

というわけでアニメーションを付けてみます。アニメーションを付ける方法は至極簡単です。呼び出されてレンダリングされるViewに対して少しコードを追加します。

struct 呼び出されるView: View {
    var body: some View {
        GeometryReader { geometory in
            [Viewの中身]
            .frame(width: geometory.size.width,height: geometory.size.height)
            .animation(.easeInOut(duration: 0.3))
        }
        .transition(.move(edge: .bottom))
    }
}

GeometryReaderを使うと、親Viewや自身のサイズ・座標を知ることができるらしい。ここでは呼び出し元のViewサイズを取得し、そのサイズに基づいて自身のアニメーションを行っているということになるようです(おそらく)。

animationでどういう風にアニメーションを行うかを指定します。

最後にtransitionで実際にアニメーションを実行します。

出し入れの挙動

Viewを出すときと仕舞うときで、不思議なことにコードを分ける必要はなさそうです。ホント不思議。

UIView.animateのときはアニメーション開始時と終了時のframeを指定する必要が有ったような気がします。

推測ですが、geometory辺りがゴニョゴニョにしているのだと思います。
アニメーション実行する瞬間のgeometoryの中身を捕まえようと試行錯誤しています。これが捕まえられれば、どういう仕組みかが理解できそうなのですが……

アニメーションの種類

.animation(.easeInOut(duration: 0.3))

.easeInOut.easeIn.easeOut.linear辺りはUIViewのアニメーションで見覚えがあるので、おおよその動きは想像つきます。

目新しいのはspring関係で、特に気になるのがinterpolatingSpringです。
これだけやけに引数が多く、4つもあります。springというだけあってバネのようにびよんびよんと動くのだろうと推測できます。

massはバネ(Spring)にかかる荷重、initialVelocityは初速です。stiffnessはバネ定数ですね。
フックの法則懐かしい。

dampingはいわゆる減衰係数ですね。
さっくりというと、バネがびよんびよんするのを押し止める度合いです。
なので、この値が大きいほど、びよんびよんしにくくなります。極端に大きくすると、ぬーっと動いてそっと止まります。

詳しいことは工学的な分野の方におまかせします。バネマスダンパや減衰振動で調べてみると良いかもしれません。あまり書くとボロが出るので書きません。

まとめ

まぁかなり脱線しましたが、画面全体のView切り替えには.easeInOut.easeIn.easeOut.linear辺りで十分だと思います。

spring系は何かアイコンを動かすなど、部分的に動かすときに使えそうです。画面全体のアニメーションでは使いにくい印象です。

interpolatingSpringに与えるパラメータを用いた計算式があれば何秒ぐらいで止まるかが分かったりするのでしょうが、ちょっと調べたところではでてきませんでした。減衰振動に関する計算式はあるので、それをベースにパラメータを変えながら試行実験をしていくしかなさそうですね。

ちょっとした実験

気になるinterpolatingSpringで少し遊んでみました。

バネにおもりを付けて天井から吊るしたものを用意します。現実世界にて、このブツのおもりを引っ張って離すと、しばらくびよんびよんした後、動かなくなります。これはブツの周りに空気があるので、この空気がダンパの役割を担っていることになります。つまり、dampingがゼロより大きい値になっていることを意味しています。

ちなみに具体的な値は知りません。空気の粘性とかを調べてみると良いかと思います。こういうの考慮し始めると、高校の物理がかなりシンプルに見えてきます。

では、dampingをゼロにしたらどうなるか?仮想世界(=アプリの中)で試してみました。

当然といえば当然ですが、減衰しないのでアニメーションが止まりませんでした。画面全体で使ってしまうと、アプリ自体が使い物にならないです。
まるで一昔前のジョークアプリのようですね。