AndroidのTranslateAnimationでリアルに(Property Animationのように)アニメーションするには?
昨日はAndroid上のTranslateAnimationのクセについて学び、無事ターゲットをリアルに(Property Animationのように)アニメーションしながら動かすことができた。
琴線探査: AndroidのTranslateAnimationのクセはひどいね
昨日のコードのmoveTarget()メソッドは相対座標系に対する移動だった。いわばmoveRelative()とでも呼ぶべきものだった。そこで今度は親コンテナの座標系に対する移動をやってみた。
「target」と表示されている赤い四角が、画面上でタップした場所に移動するというサンプル。
Eclipseプロジェクトファイル:TransformAnimationMoveTo.zip(192KB)
res/layout/main.xml
TransformAnimationMoveToActivity.java
第1のポイントは、moveTo()で引数として取得したx、yをそれぞれfinal変数のtoX、toYに格納しているところ。こうしないとAnimationListenerから参照できない。
第2のポイントは、new TranslateAnimation(left, toX, top, toY)。相対座標系での移動の場合と違って特に何を計算するでもなく単にtoX、toYを与えている。
ポイントというほどのことではないが、onTouchEvent()でActivityに対するMotionEventを取得しているので、上の方のバーやらなんやらで実際の表示領域(ターゲットの親コンテナ)の座標系と合わないため、画面サイズと親コンテナサイズの差分を取ってオフセット計算した。
琴線探査: AndroidのTranslateAnimationのクセはひどいね
昨日のコードのmoveTarget()メソッドは相対座標系に対する移動だった。いわばmoveRelative()とでも呼ぶべきものだった。そこで今度は親コンテナの座標系に対する移動をやってみた。
「target」と表示されている赤い四角が、画面上でタップした場所に移動するというサンプル。
Eclipseプロジェクトファイル:TransformAnimationMoveTo.zip(192KB)
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/parent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/target"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#660000"
android:gravity="center"
android:text="target"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
TransformAnimationMoveToActivity.java
package jp.example;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
public class TransformAnimationMoveToActivity extends Activity {
// 移動アニメーションさせるターゲット
protected View target;
// ターゲットの親コンテナ
protected View parent;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
parent = findViewById(R.id.parent); // 親コンテナ取得
target = findViewById(R.id.target); // ターゲット取得
} // END onCreate()
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
// 親コンテナの画面に対する描画位置オフセットを計算
Display disp = getWindowManager().getDefaultDisplay();
int offsetX = disp.getWidth() - parent.getWidth();
int offsetY = disp.getHeight() - parent.getHeight();
// 移動先を計算(オフセットとターゲットの中心点を考慮)
int toX = (int) (event.getX() - offsetX - target.getWidth() / 2);
int toY = (int) (event.getY() - offsetY - target.getHeight() / 2);
// タッチアップでターゲット移動
moveTo(toX, toY);
Log.v("onTouchEvent", "ACTION_UP x=" + target.getLeft() + " y=" + target.getTop() + " offsetX=" + offsetX + " offsetY=" + offsetY + " toX=" + toX + " toY=" + toY);
break;
} // END switch
return super.onTouchEvent(event);
} // END onTouchEvent()
/**
* ターゲットを指定の場所に移動する
*
* TranslateAnimationで移動アニメーションをすると、 見かけ上は移動したように見えるが実際には移動していないらしい。
* そこで、アニメーション完了時にlayout()を使って物理的にも移動させる。
*
* @param x
* X軸に対する移動先
* @param y
* Y軸に対する移動先
*/
protected void moveTo(int x, int y) {
if (target.getAnimation() != null) {
return; // アニメーション中なら何もしない
}
final int left = target.getLeft();
final int top = target.getTop();
final int toX = x; // AnimationListenerから参照できるように
final int toY = y; // AnimationListenerから参照できるように
TranslateAnimation anim = new TranslateAnimation(left, toX, top, toY);
anim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
target.layout(toX, toY, toX + target.getWidth(), toY + target.getHeight()); // 物理的にも移動
target.setAnimation(null); // これをしないとアニメーション完了後にチラつく
parent.invalidate(); // 後ろに残る残像?ゴミ?をクリアする(実行環境によるみたい)
}
});
anim.setDuration(500); // セットしないとアニメーションしない
target.layout(0, 0, target.getWidth(), target.getHeight()); // 初期位置に戻す。これをしないと2度目以降のアニメーションがおかしくなる(チラつく)
target.startAnimation(anim);
} // END moveTo()
} // END class TransformAnimationMoveToActivity
第1のポイントは、moveTo()で引数として取得したx、yをそれぞれfinal変数のtoX、toYに格納しているところ。こうしないとAnimationListenerから参照できない。
第2のポイントは、new TranslateAnimation(left, toX, top, toY)。相対座標系での移動の場合と違って特に何を計算するでもなく単にtoX、toYを与えている。
ポイントというほどのことではないが、onTouchEvent()でActivityに対するMotionEventを取得しているので、上の方のバーやらなんやらで実際の表示領域(ターゲットの親コンテナ)の座標系と合わないため、画面サイズと親コンテナサイズの差分を取ってオフセット計算した。
コメント
コメントを投稿