Androidで、プログラムコードからTranslateAnimationを使うときの注意点。
TranslateAnimationをプログラムから使う場合、コンストラクタには以下の二つのコンストラクタがあります。
- public TranslateAnimation (float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)
- public TranslateAnimation (int fromXType, float fromXValue, int toXType, float toXValue, int fromYType, float fromYValue, int toYType, float toYValue)
# いちおうpublic TranslateAnimation (Context context, AttributeSet attrs) というコンストラクタもありますがこれはどちらかというとXMLを読み込んでどうこうするためのものなので省略。
やりたいこと
で、このTranslateAnimatiを使って以下のようなアニメーションを実現したい。二つ目のコンストラクタで全てTranslateAnimation.ABSOLUTEを指定すれば良いだろー と思ってたら結構ハマったのでメモ。
なお、図形は手動で移動可能であるため、「現在の位置から特定の座標へ」移動させる必要があります。
考えた解決案(間違い)
上のようなアニメーションを指定する場合、まずこんな風に書けばいい と思うでしょう(思ってました)。
- X位置は一切移動しないので、fromXTypeとtoXValueはTranslateAnimation.RELATIVE_TO_SELF、fromXValueとtoXValueは0
- Y位置は現在位置から下に移動するので、fromYTypeはTranslateAnimation.ABSOLUTEで、fromYValueは現在のビュー座標
- Y位置は移動したい場所が決まっているので、toYTypeはTranslateAnimation.ABSOLUTEで、toYValueは移動したい座標
で、この方針でコードを書くと、大体次のような感じになった。
TranslateAnimation anim = new TranslateAnimation(
TranslateAnimation.RELATIVE_TO_SELF, 0,
TranslateAnimation.RELATIVE_TO_SELF, 0,
TranslateAnimation.ABSOLUTE, /* 今のビュー座標 */,
TranslateAnimation.ABSOLUTE, /* 移動したいビュー座標 */);
ただしこのようにすると、移動開始位置によってアニメーションと移動位置と終点がずれてしまい、上手く動きません。
Androidのソースコードまで追って色々調べてみたのですが、結論にはたどり着けなかった。
真相
どう説明すれば良いかいまいちよく分かってないですが、fromXValue, fromYValueには移動元の 親ビューの左上を基準とした 座標値(現在位置の場合は、fromXType, fromYTypeの値にかかわらず0)、移動したい場所の 現在位置からの 相対値を指定します。これは、toXTypeやtoYTypeに何を指定した場合であっても変わりません。なので、次のような形が正しい。
TranslateAnimation anim = new TranslateAnimation(
TranslateAnimation.RELATIVE_TO_SELF, 0,
TranslateAnimation.RELATIVE_TO_SELF, 0,
TranslateAnimation.RELATIVE_TO_SELF, 0,
TranslateAnimation.ABSOLUTE, /* 移動したいビュー座標 - 今のビュー座標 */);
となります(fromYValueの座標は「今のビュー座標から下に移動させたい」のでこうなってますが、上に移動させる場合は逆になります)。こうすればちゃんと目的通りに移動します。
TranslareAnimation.ABSOLUTEという名前から「常にビュー左上からの絶対値だ」と思っていましたが、そういうわけではないようですね。
真相
また、Androidのソースコードを見てみると、四つの「~Type」の引数は、次のように扱われています。
protected float resolveSize(int type, float value, int size, int parentSize) {
switch (type) {
case ABSOLUTE:
return value;
case RELATIVE_TO_SELF:
return size * value;
case RELATIVE_TO_PARENT:
return parentSize * value;
default:
return value;
}
}
#TranslateAnimationクラス自体では、この値は処理されておらず、そのままAnimationクラスのメソッドで処理されているようです。ここもちょっとびっくりでしたねー。
要するに、「~Value」のところに0を指定した時の挙動は、何をしても同じなのです(0に何を掛けても0 なので)。アニメーションのどこかでTranslateAnimation.ABSOLUTEを指定しなければいけないとき以外はプログラムコード側からクラスを使って作る必要なさそうですね。
今回勉強したこと
- アニメーションの始点の値に開始時の値を使う場合は とりあえず0 を指定する
- アニメーションの終点の値は 常に現在の値からの相対値 となる
まあ、Animationは無理せずXMLを使いましょう(と、いうより可能ならPropertyAnimationを使いましょう)。どうしても使わなきゃいけないときは特性をちゃんと理解しましょうね。
ちなみに
一つ目のコンストラクタは「~~Delta」とか書いてあるので一見割合か何かを指定するように見えるのですが、ソースコードを見てみると、実は二つ目のコンストラクタの「~~Type」の値をTranslateAnimation.ABSOLUTE
に設定してるだけです。
public TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta) {
mFromXValue = fromXDelta;
mToXValue = toXDelta;
mFromYValue = fromYDelta;
mToYValue = toYDelta;
mFromXType = ABSOLUTE;
mToXType = ABSOLUTE;
mFromYType = ABSOLUTE;
mToYType = ABSOLUTE;
}
現在値からどこかに移動させたい という場合は、こちらでも良さそうですね。