backport

技術ネタと野球とときどき雑談

AndroidでActivity切り替え時にアニメーションしたい

2017-01-17
development Android

AndroidでActivity切り替え時にアニメーションさせたくて調べてたんですが、ややこしくてだいぶ混乱しました。 Androidはもともとアニメーション周りが弱くて、バージョンが上がるたびに違ったやり方で強化した結果、統一感がなくなってる印象。

全貌を解き明かす気はないので、今回は「Activity切り替え時に比較的シンプルなアニメーションを適用する」ことに絞って調べてみました。ターゲットはAndroid4系以降です。

とりあえず分かったこと。

  • アニメーションの指定は「次に表示するActivityの出現用」「いま表示しているActivityの消失用」の2つがセット
  • startActivity()やfinish()の後にoverridePendingTransition(int enterAnim, int exitAnim)を呼ぶのが昔ながらのやり方
  • themeとしてアニメーションを指定することもできる
  • アニメーションの中身(どのようなアニメーションをするか)はxmlで定義するのが王道

overridePendingTransitionだとハードコーディングになるのでtheme化するのがよさそうです。

<!-- Activityをアニメーションさせるためのstyle -->
<style name="Animation.Standard" parent="android:Animation.Activity">
    <item name="android:activityOpenEnterAnimation">@anim/fade_in</item>
    <item name="android:activityOpenExitAnimation">@anim/fade_out</item>
    <item name="android:activityCloseExitAnimation">@anim/fade_out</item>
    <item name="android:activityCloseEnterAnimation">@anim/fade_in</item>
</style>

<!-- styleが適用されたtheme -->
<style name="AnimatedTheme" parent="AppTheme">
    <item name="android:windowAnimationStyle">@style/Animation.Standard</item>
</style>

OpenEnterとOpenExitがActivity表示時、CloseExitとCloseEnterがActivity消失時ですね。それぞれに今のActivityと次のActivityがあるので合計4つ指定することになります。

あとはAndroidManifest.xmlでApplication全体なりActivity個別なりにAnimatedThemeを適用すればOK、のはずだったんですが、ここで落とし穴が。試してみたらActivityの消失時アニメーションが適用されません。

Why my close activity animation doesn’t work on Android 4.0 (ICS) - Stack Overflow

どうやらICSのバグっぽい。C Jamesさんが提示してくれているworkaroundほぼそのままですが、以下のようなコードを書いたら無事動くようになりました。

private int closeEnterAnimationId;
private int closeExitAnimationId;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_test);
    TypedArray activityStyle = getTheme().obtainStyledAttributes(new int[]{android.R.attr.windowAnimationStyle});
    int windowAnimationStyleResId = activityStyle.getResourceId(0, 0);
    activityStyle.recycle();

    activityStyle = getTheme().obtainStyledAttributes(windowAnimationStyleResId, new int[]{android.R.attr.activityCloseEnterAnimation, android.R.attr.activityCloseExitAnimation});
    closeEnterAnimationId = activityStyle.getResourceId(0, 0);
    closeExitAnimationId = activityStyle.getResourceId(1, 0);
    activityStyle.recycle();
}

@Override
public void finish() {
    super.finish();
    overridePendingTransition(closeEnterAnimationId, closeExitAnimationId);
}

Material Designっぽいアニメーションなど、もっと凝ったことをしようとするとActivity Transitionsやらなにやらが必要になってきますが、シンプルに画面全体をアニメーションするのであれば今回の内容で事足りるはず。



コメント欄を表示する