AndroidのアニメーションTIPS

こんばんは、牧野です。
ここのところ2、3ヶ月くらい、古典に興味がわいています。中学や高校の授業で勉強する、いわゆる古文の範囲です。百人一首を覚えたり、枕草子の現代語訳を読んだりしています。1000年以上前に書かれたものなのに、今でも共感できることがたくさんあったり、そうでないものも感性や文化の違いがわかっておもしろいです。
それに関連して、先月あたりから休日と仕事後の時間を使って百人一首のAndroidアプリを作っていました。今回は普段となるべく違うことがしたくて、Javaを使いました。

ということで、今日はインフラネタではなく、アプリ作成で使ったAndroidのアニメーションについて書きたいと思います。

■回転しながら移動するアニメーション
百人一首のアプリでは、取り札にタッチするとその札を回転させながら画面外に飛ばすようにアニメーションしています。
取り札をそれぞれ一つのTextViewで作っていて、そのTextViewにアニメーションをセットします。
XMLでもアニメーションの挙動を記述できますが、今回はプログラム内で指定しました。
以下、アクティビティクラス内のアニメーション指定部分のサンプルコードです。


int rot = 360;
float yoko = (float)1;
float tate = (float)1;
RotateAnimation a1 = new RotateAnimation(0, rot,
    Animation.RELATIVE_TO_SELF, 0.5f,
    Animation.RELATIVE_TO_SELF, 0.5f);
a1.setDuration(time);
a1.setInterpolator(new DecelerateInterpolator());
TranslateAnimation a2 = new TranslateAnimation(
    Animation.RELATIVE_TO_PARENT, 0,
    Animation.RELATIVE_TO_PARENT, yoko,
    Animation.RELATIVE_TO_PARENT, 0,
    Animation.RELATIVE_TO_PARENT, tate);
a2.setDuration(time);
a2.setInterpolator(new DecelerateInterpolator());
AnimationSet as = new AnimationSet(false);
as.addAnimation(a1);
as.addAnimation(a2);
as.setFillAfter(true);
TextView Torifuda1 = (TextView)findViewById(R.id.torifuda1);
torifuda1.bringToFront();
torifuda1.startAnimation(as);

RotateAnimationのコンストラクタの引数は、順に
 回転開始角度、回転終了角度、
 回転中心点(x座標)の指定タイプ、回転中心点(x座標)の指定値、
 回転中心点(y座標)の指定タイプ、回転中心点(y座標)の指定値
です。上の例では、取り札の中心を回転中心として、360度回転します。

TranslateAnimationのコンストラクタは、
 移動開始x座標の指定タイプ、移動開始x座標の指定値、
 移動終了x座標の指定タイプ、移動終了x座標の指定値、
 移動開始y座標の指定タイプ、移動開始y座標の指定値、
 移動終了y座標の指定タイプ、移動終了y座標の指定値
です。上の例では、元々あった位置から、縦横それぞれ親ビューの高さ、幅分を直線で斜めに移動します。

setInterpolatorメソッドでは、それぞれアニメーションの速度変化を指定しています。引数にDecelerateInterpolatorクラスのインスタンスを渡すと、最初速くてだんだんゆっくりになるアニメーションになります。

ポイントは、AnimationSetにTranslateAnimationとRotateAnimationを追加する時の順番です。
取り札を回転させながら直線上を移動させる場合は、先にRotateAnimationをAnimationSetに追加します。逆にすると、かるたの向きに合わせて移動する方向が変わってしまい、うずまきのような軌道でかるたが飛ぶアニメーションになります。。

最初はこのことに気付かず、画面全体を覆うFrameLayoutを作ってそこにアニメーションさせるかるただけをのせ、回転はかるたのビューにセットして実行、かるたの移動は追加したFrameLayoutにTranslateアニメーションをセットして実行、というようなことをやっていました。。。
あと、親ビューの枠を飛び出してもアニメーションが表示されるようにするために、親ビューのFrameLayoutのxml属性に、android:clipChildren="false"を入れています。

レイアウトxmlの例


<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/p_board"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:clipChildren="false"
    android:background="@drawable/player_back"
>
<TextView
    android:id="@+id/torifuda1"
    android:layout_width="@dimen/karuta_width"
    android:layout_height="@dimen/karuta_height"
    android:background="@drawable/karuta_back"
    android:text="(下の句)" />
...

■アクティビティ間のアニメーション
アクティビティ遷移時のアニメーションを指定する時は、ActivityクラスのoverridePendingTransitionメソッドを使用しています。


intent = new Intent(TopActivity.this, HelpActivity.class);
startActivity(intent);
overridePendingTransition(R.anim.top_fadein, R.anim.top_fadeout);
finish();

xmlファイル(top_fadein.xmlとtop_fadeout.xml)で、フェードイン、フェードアウトアニメーションを用意しています。
top_fadein.xml


<alpha
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="200"
    android:startOffset="2500"
    android:fromAlpha="0.0"
    android:toAlpha="1.0" />

top_fadeout.xml


<alpha
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1200"
    android:startOffset="400"
    android:fromAlpha="1.0"
    android:toAlpha="0.0" />

…が、これだけだとAndroidのバージョンによっては正しく動かない場合があるようです。
結局、テーマを作ってアクティビティに適用するというのを併用したところ、確認で使用した端末ではうまくいったので、それで実装しています。
テーマについては以下のページにわかりやすくまとまっていました。
http://www.adamrocker.com/blog/289/activity_open_close_animation.html

・画面が回転する場合
画面の向きを指定する等で画面が回転すると、アクティビティ間のアニメーションが表示されなくなります。
縦向きのトップ画面、横向きのゲーム画面でもアニメーションされるように、遷移前のアクティビティと遷移後のアクティビティの間に暗転した画面用のアクティビティを用意しました。
画面が真っ暗になったところで画面の向きをプログラムで横向きに変更し、その後にフェードインアニメーションでゲームトップ画面に遷移するようにしています。
プログラム内で画面の向きを変更する時は、setRequestedOrientationメソッドを使います。


setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

また、デフォルトでは画面の向きが変わるとそのアクティビティが再度実行され、同じアクティビティが二重に実行されることになります。それを防ぐために、AndroidManufest.xmlに以下のようにconfigChangesを追加しています。


<activity android:name="ScreenChangeActivity"
    android:theme="@style/ScreenChangeTheme"
    android:configChanges="orientation|keyboardHidden">
</activity>

これで、画面回転時のアクティビティ再生成が防げるはずです。
この場合、画面回転時はアクティビティ再生成のかわりにonConfigurationChangedメソッドが呼ばれるので、画面回転時に何か処理したい場合はこのメソッドをオーバーライドします。

まだいくつかTIPSがあるのですが、続きはまた別の機会に書きたいと思います。

作った百人一首アプリは、先日ベータ版としてAndroidマーケットで公開しました。興味がある方は、ぜひ使ってみて下さい。Androidマーケットで「百人一首」で検索すると出てくると思います。アイコンは、弊社の和田が驚くべき早さで作ってくれました。

アプリは、もともと自分の暗記、練習用に作ろうと思ったもので、百人一首を知らない人にはあまりおすすめできないです。
百人一首が初めての人には、以下の本がおすすめです。
田辺聖子の小倉百人一首 (角川文庫、田辺 聖子)
こんなに面白かった「百人一首」 (PHP文庫、吉海 直人)

こちらは、漫画です。どちらの作品もアニメ化されています。
ちはやふる(講談社、末次 由紀)
超訳百人一首 うた恋い。(メディアファクトリー、杉田 圭)