アニメーションの実装方法についてまとめました

Androidのアニメーションに関するチュートリアル

この記事はraywenderlich.comのページを翻訳したものです。

以前にAndroidのアニメーションの実装がややこしい話しをしましたので今後案件で雑に設計しないように自分のメモがわりに記載しました。

iOSエンジニアから見たAndroidアプリ開発とiOSアプリ開発の違いについて説明します

もちろん、誤字脱字があればご連絡頂ければと思います。

前置き

アニメーション要素のないモバイルエクスペリエンスは想像しにくいです。それらは楽しくて美しく、ユーザーを適切にアプリの使い方を導くだけでなく、スクリーンを生き生きとさせる力を持っています。

画面上のオブジェクトを生き生きとさせるビルドアニメーションの実装は、最初は航空宇宙工学のように見えるかもしれませんが、恐れることはありません! Androidには、比較的簡単にアニメーションを作成するのに役立つツールがあります。

このチュートリアルでは、ロケットを使って宇宙へ(おそらく月に)ドッグを打ち上げ、安全に地面に戻って戻っていく実装を通して、いくつかの重要なアニメーションツールに慣れ親しむことを学びます。

これらのDogeアニメーションを作成することで、以下のことを学ぶことができます:

  • プロパティアニメーションの作成 - 最も便利で簡単なAndroidアニメーション
  • AndroidのViewを移動して消す
  • シーケンス内のアニメーションを結合するか、同時にアニメーションを開始する
  • 繰り返しと反転のアニメーション
  • アニメーションのタイミングを調整する
  • ロケット科学者の一人になる
前提条件: このAndroidチュートリアルはすべてアニメーションに関するものなので、AndroidプログラミングとKotlin、Android StudioXMLレイアウトの知識が必要です。Androidが初めての方は、最初にAndroid開発パート1をチェックしてみてください。

多くのアニメーション。 そのようなコード。 高速ロケット。

はじめに

アニメーションはなんて楽しい話題でしょうか! ビルドアニメーションを習得する最善の方法は、コードで手を汚すことです。(笑)

まず、Rocket Launcher Starterをダウンロードします。それをAndroid Studio 3.0 Beta 7以降のバージョンで読み込んでから、あなたの端末で実行してください。あなたはすぐに実行するための必要なものをすべてを見つけるでしょう。

アプリをビルドするとデバイス上で、実装するすべてのアニメーションのリストが表示されます。

list.png

リストの項目をクリックします。

doge_rocket.png

Dogeとロケットの2つの静的画像が表示され、Dogeは乗る準備ができています。 現時点では、すべての画面は同じで、まだアニメーションはありません。

プロパティアニメーションはどのように機能するか

最初のアニメーションの作業をする前に、理論の道を歩き、魔法の背後にある論理を明確にしておきましょう。

ロケットの打ち上げを画面の下端から上端までアニメーションする必要があり、ロケットが正確に50ミリ秒で作れると想像してください。

時間の経過と共にロケットの位置がどのように変化するかをプロットしたグラフがあります:

linear-interpolator.gif

上のアニメーションは滑らかで連続的です。 しかし、スマートフォンはデジタルであり、離散値で動作します。 時間はアニメーションのために継続的には流れません。 それは小さなステップで進歩します。

アニメーションは、フレームとも呼ばれる多くの静止画で構成され、指定された時間で1つずつ表示されます。 今回のコンセプトは最初の漫画と同じですが、レンダリングは少し異なります。

フレーム間の経過時間はフレームリフレッシュ遅延と呼ばれ、プロパティアニメーションのデフォルトでは10ミリ秒です。

ここではアニメーションが映画の初期の時代とは違っています:ロケットが一定速度で動いていることがわかっているときは、いつでもロケットの位置を計算できます。

下に示す6つのアニメーションフレームが表示されます。 注意として

  • アニメーションの初めに、ロケットは画面の下端にあります。
  • ロケットの位置はすべてのフレームでそのパスの同じ部分だけ上に移動する
  • アニメーションが終わるまでに、ロケットはスクリーンの上端にあります。

frames.png

TL / DR:与えられたフレームを描くとき、継続時間とフレームリフレッシュレートに基づいてロケットの位置を計算します。

幸いにも、ValueAnimatorがあなたのためにやってくれているので、すべての計算を手動で行う必要はありません。

アニメーションを設定するには、アニメーション化されるプロパティの開始値と終了値、および継続時間を指定するだけです。 また、コールするリスナーを追加する必要があります。これにより、各フレームのロケットの新しい位置が設定されます。

Time Interpolators(タイムインターポレータ)

あなたはおそらく、ロケットがアニメーション全体で一定のスピードで動くことに気づいたでしょう - それほど現実的ではありません。 マテリアルデザインは、より自然な方法で動作しながら、ユーザーの注意を引く生き生きとしたアニメーションを作成することを奨励します。

Androidのアニメーションフレームワークでは、Time Interpolatorsを使用しています。 ValueAnimatorはTime Interpolatorインターフェイスを実装するオブジェクトを持っています。 時間補間器は、時間の経過とともにアニメーション値がどのように変化するかを決定します。

最も単純なケースでは、経時的な位置変化のグラフをもう一度見直してください。(Linear Interpolator)

linear-interpolator_1.gif

このLinearInterpolatorが時間の変化にどのように応答するかは次のとおりです。

table_linear.png

時間に依存して、ロケットの位置は一定の速度で変化するか直線的に変化します。

accelerate-interpolator.gif

アニメーションは、非線形補間器を有することもできる。 このような例の1つがAccelerateInterpolatorです。

table_acc.png

これは入力値を2乗することでロケットがゆっくりと加速し、素早く加速するようにします。実際のロケットのように!

それはあなたが始めるために知っておく必要がある理論のほとんどがすべてです。今のところはね。。。

Your First Animation

あなたが移動する前に、プロジェクトに慣れるためにしばらく時間をかけてください。com.raywenderlich.rocketlauncher.animationactivitiesパッケージには、BaseAnimationActivityと、このクラスを拡張するその他すべてのアクティビティが含まれています。

res/layoutフォルダ内のactivity_base_animation.xmlファイルを開きます。

ルートには、画像付きのImageViewの2つのインスタンスが含まれているFrameLayoutがあります.1つはrocket.png、もう1つはdoge.pngです。どちらもAndroid:layout_gravitybottom|center_horizontalを設定して、画像を画面の下の中央に描写します。

このチュートリアルでは、多くのファイルナビゲーションを行います。 Android Studioでこれらの便利なショートカットを使用して、物事間を簡単に移動させることができます。
LinuxWindowsの場合は、 Ctrl + Shift + Nで、Macの場合は、command + shift + Oで任意のファイルに移動します
LinuxWindowsの場合は、 Ctrl + NMacの場合には、コマンド+ Oを使用してKotlinクラスに移動する

BaseAnimationActivityは、このアプリケーション内の他のすべてのアニメーションアクティビティのスーパークラスです。

BaseAnimationActivity.ktを開き、内部を見てください。 一番上には、すべてのアニメーションアクティビティからアクセス可能なViewメンバ変数があります。

  • rocketはロケットのイメージを持つビューです
  • dogeはDogeの画像を含むビューです
  • frameLayoutは、rocketdogeの両方を含むFrameLayoutです。
  • screenHeightは、便宜上、画面の高さと同じになります

rocketdogeはどちらもImageViewの一種ですが、プロパティアニメーションはすべてのAndroidビューで動作するため、それぞれをViewとして宣言しています。 ビューはまた、レイアウトが膨張され、例えば、ActivityのonCreate()のような適切なライフサイクルイベントにバインドされるまでnullであるため、lateinit値として宣言されます。

onCreate()を見てコードを観察してください:

sample.kt
// 1
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_base_animation)

// 2
rocket = findViewById(R.id.rocket)
doge = findViewById(R.id.doge)
frameLayout = findViewById(R.id.container)

// 3
frameLayout.setOnClickListener { onStartAnimation() }

ここでは、このコードで何が起こっているのかというと

  1. スーパークラスonCreate()を呼び出し、レイアウトファイルでSetContentView(...)を呼び出します。
  2. XMLレイアウトを適用し、FrameLayoutrocket、およびdogeを対応するビューにバインドします。
  3. FrameLayoutonClickListenerを設定します。
  4. ユーザーが画面をタップするたびにonStartAnimation()を呼び出します。 これは、BaseAnimationActivityを拡張する各Activityによって定義されるabstractメソッドです。

この基本コードは、このチュートリアルで編集するすべてのアクティビティで共有されます。 これであなたはそれに精通しているので、今こそカスタマイズを開始するときです!

Launch the Rocket

あなたがロケット打ち上げを開始しない限り、Dogeはどこにも行かないので、それはとても簡単で始めるには最高のアニメーションです。 ロケット科学はとてもシンプルだと誰が思ったでしょうか?

LaunchRocketValueAnimatorAnimationActivity.ktを開き、次のコードをonStartAnimation()の本文に追加します。

LaunchRocketValueAnimatorAnimationActivity.kt
//1
val valueAnimator = ValueAnimator.ofFloat(0f, -screenHeight)

//2
valueAnimator.addUpdateListener {
  val value = it.animatedValue as Float
  rocket.translationY = value
}

//5
valueAnimator.interpolator = LinearInterpolator()
valueAnimator.duration = BaseAnimationActivity.Companion.DEFAULT_ANIMATION_DURATION

//6
valueAnimator.start()
  1. 静的メソッドforFloatを呼び出して、ValueAnimatorインスタンスを作成します。時間の経過とともにアニメーションオブジェクトの指定されたプロパティに適用される浮動小数点数を受け入れます。 この場合、値は0fで始まり、-screenHeightで終わります。 Androidはスクリーン座標を左上のコーナーで開始するので、ロケットのY変換は0から画面の高さの負に変化します。つまり、下から上に移動します。
  2. addUpdateListener()を呼び出し、リスナーを渡します。 ValueAnimatorは、アニメーション化された値の更新ごとにこのリスナーを呼び出します。デフォルトの遅延は10msです。
  3. アニメーターから現在の値を取得し、floatにキャストします。 ofFloatValueAnimatorを作成したため、現在の値の型はfloatです。
  4. そのtranslationYの値を設定してロケットの位置を変更します。
  5. アニメータの時間とinterpolatorを設定します。
  6. アニメーションを開始します。

ビルドして実行します。 リストからLaunch a Rocketを選択します。 新しい画面が表示されます。 それをタップしましょう!

linear-launch.gif

それは楽しいよね? :]Dogeが残っていることを心配しないでください - 彼は少し後に月に彼のロケット船をキャッチしにいきます。

Put a Spin on It

ロケットに少し回転動作を与えるのはどうですか? RotateRocketAnimationActivity.ktを開き、次のコードをonStartAnimation()に追加します。

RotateRocketAnimationActivity.kt
// 1
val valueAnimator = ValueAnimator.ofFloat(0f, 360f)

valueAnimator.addUpdateListener {
  val value = it.animatedValue as Float
  // 2
  rocket.rotation = value
}

valueAnimator.interpolator = LinearInterpolator()
valueAnimator.duration = BaseAnimationActivity.Companion.DEFAULT_ANIMATION_DURATION
valueAnimator.start()

違いを見つけることができますか?
1. valueAnimatorの値を0fから360fに変更すると、ロケットは完全な回転になります。 0fから180fに変更することでUターンエフェクトを作成することができます。
2. translationYを設定する代わりに、ロケットのrotation(回転)を設定するのは、それが変更する必要があるためです。

ビルドして、実行し、Spin a rocketを選択します。 新しい画面が表示されたらタップしましょう。

spin.gif

Accelerate the Launch

AccelerateRocketAnimationActivity.ktを開き、あなたの旧友onStartAnimation()に次のコードを追加してください:

AccelerateRocketAnimationActivity.kt
// 1
val valueAnimator = ValueAnimator.ofFloat(0f, -screenHeight)
valueAnimator.addUpdateListener {
  val value = it.animatedValue as Float
  rocket.translationY = value
}

// 2 - Here set your favorite interpolator
valueAnimator.interpolator = AccelerateInterpolator(1.5f)
valueAnimator.duration = BaseAnimationActivity.DEFAULT_ANIMATION_DURATION

// 3
valueAnimator.start()

上記のコードは、LaunchRocketValueAnimationActivity.ktonStartAnimation()と同じですが例外が1行です。valueAnimator.interpolatorの設定に使用されたインターポレータの部分です。

ビルドして実行してみましょう。リスト内のAccelerate a rocketを選択します。 新しいスクリーンをタップすると、ロケットの動きを確認できます。

再び、私たちは、貧しいDogeが月にロケットを捕まえていないことが分かります...貧しいfella。 そこにハングアップ、バディ!

accelerate.gif

AccelerateInterpolatorを使用しているので、離陸後にロケットが加速しているのを確認する必要があります。 あなたが望むならば、interpolatorsで遊んでも構いません。 私はここに座って待ちます。 約束しましょう。

Which Properties Can You Animate?

これまではViewの位置と回転だけをアニメーション化しましたが、ValueAnimatorは、その値を使って何をしているかは気にしません。

ValueAnimatorに、次のいずれかのタイプを使用して値をアニメーションさせるように指示できます。

  • ofFloatValueAnimatorインスタンスを作成する場合はfloat
  • intの場合はint
  • ofObjectは、floatまたはintが十分でない場合に使用されます。色をアニメーション化するためによく使用されます

Viewの任意のプロパティをアニメーションさせることもできます。 いくつかの例があります:

  • scaleXおよびscaleY - ビューをx軸またはy軸で個別に拡大/縮小させることができます。または、両方を同じ値で呼び出して、ビューのサイズをアニメーションできます。
  • translationXおよびtranslationY - これらを使用すると、ビューの画面上の位置を変更できます。
  • alpha - ビューの透明度をアニメーションさせる。 0は完全に透明であり、1は完全に不透明である。
  • rotation - 画面上のビューを回転させます。 引数は度であり、360は完全な時計回りの回転を意味します。 負の値を指定することもできます。たとえば、-90は反時計回りの1/4回転を意味します。
  • rotationXrotationY - rotationと同じですが、x軸とy軸に沿っています。 これらのプロパティを使用すると、3Dで回転できます。
  • backgroundColor - 色を設定します。 整数の引数は、Androidの定数Color.YELLOWColor.BLUEと同じ色を指定する必要があります。

ObjectAnimator

ValueAnimatorのサブクラスであるObjectAnimatorを見てください。 1つのオブジェクトの1つのプロパティだけをアニメーション化する必要がある場合、ObjectAnimatorは新しいベストフレンドになるかもしれません。

ValueAnimatorでは、リスナーを設定して値で何かを行う必要がありますが、ObjectAnimatorはこれらのビットをほぼ自動的に処理できます。

LaunchRocketObjectAnimatorAnimationActivity.ktクラスに移動し、次のコードを入力します。

LaunchRocketObjectAnimatorAnimationActivity.kt
// 1
val objectAnimator = ObjectAnimator.ofFloat(rocket, "translationY", 0f, -screenHeight)

// 2
objectAnimator.duration = BaseAnimationActivity.Companion.DEFAULT_ANIMATION_DURATION
objectAnimator.start()

ここでやっていることは、

  1. ObjectAnimatorインスタンスを作成する(ValueAnimatorの場合のように)。ただし、前者は2つのパラメータをさらに必要とする。
  2. rocketはアニメーションのオブジェクトです。
  3. オブジェクトには、変更するプロパティの名前に対応するプロパティが必要です(この例では「translationY」です)。 rocketは、Base Javaクラスで、setTranslationY()を使用してアクセス可能なセッターを持つViewクラスのオブジェクトであるため、これを行うことができます。

  4. アニメーションの継続時間を設定して開始します。

プロジェクトを実行します。 リストでLaunch a rocket (ObjectAnimator)を選択します。 画面をタップします。

linear-launch_2.gif

ロケットはValueAnimatorと同じように動作しますが、コードは少なくなります。

ObjectAnimatorには制限があります.2つのオブジェクトを同時にアニメーション化することはできません。 この問題を回避するには、ObjectAnimatorインスタンスを2つ作成します。
ObjectAnimatorまたはValueAnimatorを使用することを決定した場合の使用例とコーディング量を考慮してください。

Animating Color

ユースケースについて言えば、アニメーションの色を考慮する必要があります。 ofFloat()inInt()も、あなたのアニメーターを構築することも、色で良い結果を得ることもできません。 あなたはArgbEvaluatorを使う方が良いです。

ColorAnimationActivity.ktを開き、このコードをonStartAnimation()に入れてください。

ColorAnimationActivity.kt
//1
val objectAnimator = ObjectAnimator.ofObject(
  frameLayout,
  "backgroundColor",
  ArgbEvaluator(),
  ContextCompat.getColor(this, R.color.background_from),
  ContextCompat.getColor(this, R.color.background_to)
)

// 2 objectAnimator.repeatCount = 1 objectAnimator.repeatMode = ValueAnimator.REVERSE

// 3 objectAnimator.duration = BaseAnimationActivity.Companion.DEFAULT_ANIMATION_DURATION objectAnimator.start()

上記のコードでは、

  1. ObjectAnimator.ofObject()を呼び出し、それに以下の引数を与えます。

  • frameLayout - アニメーション化されるプロパティを持つオブジェクト
  • backgroundColor - アニメーション化するプロパティ
  • ArgbEvaluator() - 2つの異なるARGB(アルファ、赤、緑、青)のカラー値を補間する方法を指定する追加の引数
  • Start and end color values(カラー値の開始と終了) - ここでは、ComtextCompat.getColor()を使用して、colors.xmlで指定されたカスタムなカラーのColor Resouce IDを取得します。

  1. オブジェクトのrepeatCount値を設定して、アニメーションが繰り返される回数を設定します。 次に、そのrepeatModeを設定して、アニメーションが最後に達したときの動作を定義します。 もうすぐこれについてもっと詳しく説明します!
  2. アニメーション時間を設定し、アニメーションを開始します。

ビルドして実行します。 Background colorの項目を選択し、画面をタップします。

bg-color.gif

それは素晴らしいです! Hey、あなたはこれをかなり素早くつかまえています。 それはバタフライで滑らかな背景色の変化です。

Combining Animations

ビューをアニメーション化するのはすごく素晴らしいですが、これまでは一度に1つのプロパティと1つのオブジェクトしか変更していません。 アニメーションはそれほど制限的である必要はありません。

では、Dogeを月に送る時です!

AnimatorSetを使用すると、複数のアニメーションを一緒に、または順番に再生できます。 最初のアニメーターをplay()に渡します。これは、Animatorオブジェクトを引数として受け取りビルダーを返します。

次に、そのBuilderで次のメソッドを呼び出すことができます。これらのメソッドはすべて、Animatorを引数として受け入れます。

  • with() - play()で指定した最初のものと同時に引数として渡されたAnimatorを再生するためのもの
  • before() - 前に再生する
  • after() - 後に再生する

これらのような一連の呼び出しを作成できます。

エディタでLaunchAndSpinAnimatorSetAnimatorActivity.ktを開き、次のコードをonStartAnimation()に挿入します。

LaunchAndSpinAnimatorSetAnimatorActivity.kt
// 1
val positionAnimator = ValueAnimator.ofFloat(0f, -screenHeight)

// 2 positionAnimator.addUpdateListener { val value = it.animatedValue as Float rocket.translationY = value }

// 3 val rotationAnimator = ObjectAnimator.ofFloat(rocket, "rotation", 0f, 180f) // 4 val animatorSet = AnimatorSet() // 5 animatorSet.play(positionAnimator).with(rotationAnimator) // 6 animatorSet.duration = BaseAnimationActivity.Companion.DEFAULT_ANIMATION_DURATION animatorSet.start()

このブロックであなたがやっていることは次のとおりです。
1. 新しいValueAnimatorを作成します。
2. ロケットの位置を更新するValueAnimatorにAnimatorUpdateListenerを付け加えます。
3. ロケットの回転を更新する2番目のアニメーターであるObjectAnimatorを作成します。
4. AnimatorSetの新しいインスタンスを作成します。
5. rotationAnimatorと一緒にpositionAnimatorを実行するように指定します。
6. 典型的なアニメーションと同様に、アニメーションの時間を設定してstart()を呼び出します。

もう一度ビルドして実行してください。 Launch and spin(AnimatorSet)を選択します。 画面をタップします。

launch-n-spin.gif

Dogeはこれで物理学の法則に反します。

同じオブジェクトのいくつかのプロパティを簡単にアニメーション化するための素晴らしいツールがあります。 このツールというのは、、、

ViewPropertyAnimator

ViewPropertyAnimatorを使用するアニメーションのコードの最大の特徴の1つは、書き込みと読み込みが容易だということです。

LaunchAndSpinViewPropertyAnimatorAnimationActivity.ktを開き、次の呼び出しをonStartAnimation()に追加します。

(ViewPropertyAnimator)

LaunchAndSpinViewPropertyAnimatorAnimationActivity.kt
rocket.animate()
    .translationY(-screenHeight)
    .rotationBy(360f)
    .setDuration(BaseAnimationActivity.Companion.DEFAULT_ANIMATION_DURATION)
    .start()

ここでは、animate()ViewPropertyAnimatorインスタンスを返し、呼び出しをチェインさせることができます(メソッドチェイン)。

ビルドして実行し、起動してLaunch and spin (ViewPropertyAnimator)を選択すると、前のセクションと同じアニメーションが表示されます。

このセクションのコードを、前のセクションで実装したAnimatorSetコードスニペットと比較してください。

(AnimatorSet)

LaunchAndSpinAnimatorSetAnimatorActivity.kt
val positionAnimator = ValueAnimator.ofFloat(0f, -screenHeight)

positionAnimator.addUpdateListener { val value = it.animatedValue as Float rocket?.translationY = value }

val rotationAnimator = ObjectAnimator.ofFloat(rocket, "rotation", 0f, 180f)

val animatorSet = AnimatorSet() animatorSet.play(positionAnimator).with(rotationAnimator) animatorSet.duration = BaseAnimationActivity.Companion.DEFAULT_ANIMATION_DURATION animatorSet.start()

viewanimate.png

ViewPropertyAnimatorは、複数の同時アニメーションに対してより良いパフォーマンスを提供します。 無効化された呼び出しを最適化するので、いくつかのプロパティに対しては1回しか発生しません。それぞれのアニメーション化されたプロパティとは対照的に、独立した独自の無効化を引き起こします。

Animating the Same Property of Two Objects

ValueAnimatorの優れた機能は、アニメーション化された値を再利用して、好きなだけ多くのオブジェクトに適用できることです。

FlyWithDogeAnimationActivity.ktを開き、次のコードをonStartAnimation()に入れてテストしてください。

FlyWithDogeAnimationActivity.kt
//1
val positionAnimator = ValueAnimator.ofFloat(0f, -screenHeight)
positionAnimator.addUpdateListener {
  val value = it.animatedValue as Float
  rocket.translationY = value
  doge.translationY = value
}

//2 val rotationAnimator = ValueAnimator.ofFloat(0f, 360f) rotationAnimator.addUpdateListener { val value = it.animatedValue as Float doge.rotation = value }

//3 val animatorSet = AnimatorSet() animatorSet.play(positionAnimator).with(rotationAnimator) animatorSet.duration = BaseAnimationActivity.Companion.DEFAULT_ANIMATION_DURATION animatorSet.start()

上記のコードでは、3つのアニメーターを作成しました。

  1. positionAnimator - rocketdogeの位置を変更する
  2. rotationAnimator - Dogeを回転させる
  3. animatorSet - 最初の2つのアニメーターを結合する

最初のアニメーターで2つのオブジェクトの変換を一度に設定することに注意してください。

アプリケーションを実行し、Doe behind behind(2つのオブジェクトのアニメーション)を選択しないでください。 今何をすべきかわかるはずです。 そう、月へ!

Animation Listeners

アニメーションとは通常、特定のアクションが発生したか、あるいは発生することを意味します。 通常何が起こっても、通たいていはあなたのファンシーなアニメーションの終わりが来ます。

あなたはそれを観察することはできませんが、ロケットが停止し、アニメーションが終了するとスクリーンから離れたままであることがわかります。 着陸を計画していない場合、またはアクティビティを終了する予定がない場合は、この特定のビューを削除してリソースを節約できます。

AnimatorListener - 次のイベントが発生したときにアニメータから通知を受け取ります。

  • onAnimationStart() - アニメーションの開始時に呼び出されます。
  • onAnimationEnd() - アニメーションの終了時に呼び出されます。
  • onAnimationRepeat() - アニメーションが繰り返される場合に呼び出されます。
  • onAnimationCancel() - アニメーションがキャンセルされた場合に呼び出されます。

WithListenerAnimationActivity.ktを開き、次のコードをonStartAnimation()に追加します。

WithListenerAnimationActivity.kt
//1
val animator = ValueAnimator.ofFloat(0f, -screenHeight)

animator.addUpdateListener { val value = it.animatedValue as Float rocket.translationY = value doge.translationY = value }

// 2 animator.addListener(object : Animator.AnimatorListener { override fun onAnimationStart(animation: Animator) { // 3 Toast.makeText(applicationContext, "Doge took off", Toast.LENGTH_SHORT) .show() }

override fun onAnimationEnd(animation: Animator) { // 4 Toast.makeText(applicationContext, "Doge is on the moon", Toast.LENGTH_SHORT) .show() finish() }

override fun onAnimationCancel(animation: Animator) {}

override fun onAnimationRepeat(animation: Animator) {} })

// 5 animator.duration = 5000L animator.start()

上記のコードの構造は、リスナー部分を除いて、前のセクションと同じように見えるはずです。 ここでしていることは、

  1. アニメーターを作成して設定します。ValueAnimatorを使用して、2つのオブジェクトの位置を同時に変更します。1つのObjectAnimatorで同じことをすることはできません。
  2. AnimatorListenerを追加します。
  3. アニメーション開始時にトーストメッセージを表示する
  4. 終了時には別のトーストを表示させます。
  5. いつものようにアニメーションを開始する

アプリを実行します。 Animation eventsを選択します。 画面をタップします。 メッセージを見てください!

events.gif

start()を呼び出す前に、コールチェーンにsetListenerを追加することによって、ViewPropertyAnimatorにリスナーを追加することもできます。

WithListenerAnimationActivity.kt
rocket.animate().setListener(object : Animator.AnimatorListener {
  // Your action
})

あるいは、Animate()の後にwithStartAction(Runnable)withEndAction(Runnable)を呼び出すことで、ビューの開始アクションと終了アクションを設定できます。 これらのアクションを持つAnimatorListenerと同等です。

Animation Options

アニメーションは、単に停止したり進んだりするワントリックのポニーではありません。 例えば、ループ、逆転、特定の時間実行するなどなど。

Androidでは、次の方法を使用してアニメーションを調整できます。

  • repeatCount - 最初の実行後にアニメーションを繰り返す回数を指定します。
  • repeatMode - このアニメーションが最後に達したときに何をすべきかを定義します。
  • duration - アニメーションの合計時間を指定します。

FlyThereAndBackAnimationActivity.ktを開き、次のコードをonStartAnimation()に追加します。

FlyThereAndBackAnimationActivity.kt
// 1
val animator = ValueAnimator.ofFloat(0f, -screenHeight)

animator.addUpdateListener { val value = it.animatedValue as Float rocket.translationY = value doge.translationY = value }

// 2 animator.repeatMode = ValueAnimator.REVERSE // 3 animator.repeatCount = 3

// 4 animator.duration = 500L animator.start()

ここでは、

  1. いつものようにアニメーターを作成する。
  2. repeatModeを次のいずれかに設定できます。

  • RESTART - 最初からアニメーションを再開します。
  • REVERSE - 反復ごとにアニメーションの方向を反転します。

この場合、ロケットを離陸させてから始動したのと同じ位置に戻る必要があるため、これをREVERSEに設定します。 ちょうどSpaceXのように!

  1. それを2回することを除きます。
  2. 通常どおり、アニメーション時間を設定し、アニメーションを開始します。

なぜ3番目のセクションで3回のrepeat countを指定するのですか? それぞれの上下運動は2回の繰り返しを消費するので、Dogeを2度地球に戻すには3回が必要です.1回は最初に着陸し、もう2回は着陸して再び着陸します。Dogeが跳ね返るのをどれくらいしたいですか? それで遊んでみてください!

アプリを実行します。 リスト内のFly there and back (Animation options)を選択します。新しい画面が開きます。画面をタップします。

there-and-back.gif

あなたはロケットがバッタのようにジャンプするのを見てください! それを取る、Elon Musk。

Declaring Animations in XML

あなたはこのチュートリアルの最も重要な部分を作りました。 この最後のセクションでは、一度宣言してどこでも使用する方法を学びます。そうです。あなたのアニメーションを無断で再利用できるようになります。

XMLでアニメーションを定義することで、コードベース全体でアニメーションを再利用できます。

XMLでのアニメーションの定義は、ビューレイアウトの作成と似ています。

スタータープロジェクトには、res/animatorjump_and_blink.xmlというアニメーションXMLがあります。 エディタでファイルを開くと、これが表示されます。

jump_and_blink.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:ordering="together">
</set>

次のXMLタグを利用できます

  • set - AnimatorSetと同じ
  • animator - ValueAnimatorと同じ
  • objectAnimator - あなたは正しく推測するでしょう。 ObjectAnimatorの略です。

XMLAnimatorSetを使用する場合は、レイアウトXMLファイル内のViewGroupオブジェクト(RelativeLayoutLinearLayoutなど)内にViewオブジェクトをネストする方法と同じように、その内部にValueAnimatorオブジェクトとObjectAnimatorオブジェクトをネストします。

jump_and_blink.xmlの内容を次のコードに置き換えます。

jump_and_blink.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
  android:ordering="together">

<objectAnimator android:propertyName="alpha" android:duration="1000" android:repeatCount="1" android:repeatMode="reverse" android:interpolator="@android:interpolator/linear" android:valueFrom="1.0" android:valueTo="0.0" android:valueType="floatType"/>

<objectAnimator android:propertyName="translationY" android:duration="1000" android:repeatCount="1" android:repeatMode="reverse" android:interpolator="@android:interpolator/bounce" android:valueFrom="0" android:valueTo="-500" android:valueType="floatType"/> </set>

ここで、ルート要素のsetタグを宣言します。 そのordering属性は、togetherでもsequentialでもかまいません。 デフォルトではtogetherになっていますが、明確にするために指定することをお勧めします。setタグには2つの子XMLタグがあり、それぞれはobjectAnimatorです。

objectAnimatorの次の属性を見てください。

  • android:valueFromandroid:valueTo - ObjectAnimatorインスタンスを作成したときのように開始値と終了値を指定します。
  • android:valueType - 値の型。floatTypeまたはintTypeのいずれか
  • android:propertyName - set部分なしでアニメーションするプロパティ
  • android:duration - アニメーションの長さ
  • android:repeatCount - setRepeatCountと同じです
  • android:repeatMode - setRepeatModeと同じです
  • android:interpolator - interpolatorを指定します。 通常は@android:interpolator/で始まります。 これを入力すると、Android Studioはオートコンプリートオプションの下で利用可能なすべてのinterpolatorを表示します。
  • ここであなたのターゲットオブジェクトを指定することはできませんが、後でKotlinで行うことができます

最後のブロックでは、objectAnimatorの2つのインスタンスAnimatorSetに追加し、それらは一緒に再生されます。 今、それらを使う時です。

XmlAnimationActivity.ktに移動し、次のコードをonStartAnimation()に追加します。

XmlAnimationActivity.kt
  // 1
  val rocketAnimatorSet = AnimatorInflater.loadAnimator(this, R.animator.jump_and_blink) as AnimatorSet
  // 2
  rocketAnimatorSet.setTarget(rocket)

// 3 val dogeAnimatorSet = AnimatorInflater.loadAnimator(this, R.animator.jump_and_blink) as AnimatorSet // 4 dogeAnimatorSet.setTarget(doge)

// 5 val bothAnimatorSet = AnimatorSet() bothAnimatorSet.playTogether(rocketAnimatorSet, dogeAnimatorSet) // 6 bothAnimatorSet.duration = BaseAnimationActivity.Companion.DEFAULT_ANIMATION_DURATION bothAnimatorSet.start()

上記のコードでは、いくつかのことをしています。

  1. まず、通常はビューレイアウトをinflateするのと同じように、R.animator.jump_and_blinkファイルからAnimatorSetをロードします
  2. 次に、ロードしたAnimatorをターゲットとしてロケットに設定します
  3. もう一度同じファイルからAnimatorを読み込みます。
  4. dogeオブジェクトのためにすすぎと繰り返し
  5. 今度は、3つ目のAnimatorSetを作成し、最初の2つを同時に再生するように設定します
  6. root animatorのアニメーション時間を設定して開始する
  7. すごい! 少しだけ休む

ビルドして実行します。 一覧からJump and blink (Animations in XML)を選択します。 あなたの手仕事を見るにはタップしてください。

jump-n-blink.gif

Dogeがジャンプして消えて、また地面に安全に帰ってくるのを見てください。

あとがき

これで本セクションの解説を終わります。

Happy Halloween!!!