androidアニメーションの置換メモ

自メモ)
とりあえず書いた版。適宜補強していく予定

思い立ったきっかけ)

  • 4.1以降の端末でアニメーションがおかしくなる
    • 旧形式のAnimationを使っていた

Animationクリア系の試作をしてみても改善されず

//方式1
v.clearAnimation();

//方式2
v.setImageDrawable(null); 
//setImageBitmap した bmp.recycle() しておくようにというサイトも有る

//方式3
ani.setRepeatCount(0);

ということで古いアニメーションは動作不完全 =>3系のアニメーション使いましょう
というお話もあり バックポートライブラリ nineoldandroids を試して見ることに。。

備考)
一応

anim.cancel();

みたいな関数は用意されてるけど、Animationクラスって
普通呼び出し関数内で完結してるので
AnimationListener のコールバック関数内で書かないと使い勝手が微妙ですよね‥‥(汗


今回置換に使おうとしているFW)


旧アニメーション)


3系以降のAnimation系のURLMemo)


情報的に使えるかもしれないリンク)
x位置からアニメとか

変わったアニメーション)



事前準備)

protected int m_widthPixels=0,m_heightPixels=0;
private float m_density = 0;

//画面サイズの取得
WindowManager windowManager = getWindowManager();
Display display = windowManager.getDefaultDisplay();
final DisplayMetrics displayMetrics = new DisplayMetrics();
display.getMetrics(displayMetrics);
m_widthPixels 	= displayMetrics.widthPixels;
m_heightPixels 	= displayMetrics.heightPixels;
m_density = displayMetrics.density;


//dipに変える
protected int d(int px) {
	return (int)(px*m_density);
}
//dipに変える
protected int d(double px) {
	return (int)(px*m_density);
}
  • SizeAnimation
    • 使ったこと無い‥‥‥
  • RotateAnimation
    • 180 =>360 回転

旧)

    	RotateAnimation rotate = new RotateAnimation(180, 360,
    	    	Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    	rotate.setDuration(120);
    	rotate.startAnimation(view);

新)

       ObjectAnimator.ofFloat(view, "rotation", 180, 360).setDuration(120).start()
属性
Z軸 rotation
X軸 rotationX
Y軸 rotationY

という形に拡張されているようです

  • TranslateAnimation
    • Y軸方向に差分移動

旧)

	TranslateAnimation vm = new TranslateAnimation(0, 0, 0, d(20));
	vm.setDuration(500);
	view.startAnimation(vm);
	vm.setFillAfter(true); //☆の対応がわからない?

新)

        ObjectAnimator.ofFloat(view, "translationY", 0, d(20)).setDuration(500).start();

☆に関して>
NineOld)
- Advanced Pre-Honeycomb Animation with NineOldAndroids - Jake Wharton
記述だと基底クラスで

         setFillAfter(true);  //アニメーション後、初期位置に戻らない

の記載があるので気にしないで良いよう
 <本来のObjectAnimator等もそうなっているのかな?

  • TranslateAnimation
    • X,Y軸方向に差分移動

旧>

	TranslateAnimation vm = new TranslateAnimation(0, 0, d(20), d(20));
	vm.setDuration(500);
	view.startAnimation(vm);

新)

	AnimatorSet set = new AnimatorSet();
	set.playTogether(
		ObjectAnimator.ofFloat(view, "translationX",0, d(20)),
   		ObjectAnimator.ofFloat(view, "translationY",0, d(20))
	);
	set.setDuration(500).start();

 AnimatorSet は

状態 関数名
一緒 playTogether
順番 playSequentially

新2)

	PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("translationX", d(20));
	PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("translationY", d(20));
	ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvyY).setDuration(500).start();	
座標系 属性
相対座標X translationX
相対座標Y translationY
絶対座標X x
絶対座標Y y

pivotX
pivotY
は 拡大縮小の基点 らしい

旧)

	int w = m_widthPixels;
	int h = m_heightPixels;

//ScaleAnimation(float fromX, float toX, float fromY, float toY, float pivotX, float pivotY)
	ScaleAnimation sa = new ScaleAnimation(0.7f, 1.0f, 0.7f , 1.0f, w/2, (h-50)/2);
	sa.setDuration(500);
	sa.setFillAfter(true);
	view.startAnimation(sa);

新1)

	AnimatorSet set = new AnimatorSet();
	set.playTogether(
		ObjectAnimator.ofFloat(view, "scaleX", 0.7f, 1.0f),
    		ObjectAnimator.ofFloat(view, "scaleY", 0.7f , 1.0f),
    		ObjectAnimator.ofFloat(view, "pivotX", w/2 , w/2), //★
    		ObjectAnimator.ofFloat(view, "pivotY", (h-50)/2 , (h-50)/2), //★ ココらへん不安
	);
	set.setDuration(500).start();

ちなみに

ObjectAnimator.ofFloat(view, "scaleX", 0.7f, 1.0f,0.5f)

とかくと3段階変化 「0,7f=>1.0f => 0.5f」となるそうです

新2)

  • Android 3での書き方
    • pivotX、pivotY は対応箇所見つからず。記述なくても見た目アニメ変わらない気がするんだけど、うーん><
	ViewPropertyAnimator animator = view.animate() //☆
	animator.scaleX(1.0f);
	animator.scaleY(1.0f);
	animator.setDuration(500).start();

ただし

  • NineOldAndroid の場合
//need import static com.nineoldandroids.view.ViewPropertyAnimator.animate; ?
ViewPropertyAnimator animator = animate(view);	//<= view.animate()

という記述になります

  • AlphaAnimation
    • 徐々に透明になっていく記述

旧)

	AlphaAnimation a = new AlphaAnimation(1.0f, 0.0f);
	a.setFillAfter(true);
	a.setDuration(1000);
	view.startAnimation(a);

新)

       ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", 1.0f, 0.0f);
       animator.setDuration(1000).start();

新2)

     ViewPropertyAnimator  animator = animate(view);
     animator.alpha(0).setDuration(1000).start();



  • アニメーションデータの読み込み

旧)
アニメデータは res/anim>

Animation animeJ = AnimationUtils.loadAnimation(this, R.anim.out_to_left);
view.setAnimation(animeJ);
view.startAnimation(animeJ);
  • res/anim/out_to_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:anim/accelerate_interpolator">
        <translate 
            android:fromXDelta="0%" 
            android:toXDelta="500%" 
            android:fillAfter="true"  
            android:fillEnabled="true" 
            android:duration="2000"/>
</set>

set .. AnimationSet に対応


参考URL)

特に最後のリンクの


自分自身のサイズの場合は, 10%
親Viewのサイズの場合は, 10%p
みたいな表記ができるってのは知らなかったorz。すごく勉強になるな。。

新)
アニメデータは res/animator>

View viewBall = findViewById(R.id.ball);
Animator  animeJ = AnimatorInflater.loadAnimator(this.R.animator.out_to_left);
animeJ.setTarget(viewBall);
animeJ.start();

公式との違いは import文くらいのところかも‥‥

import android.animation.AnimatorInflater.loadAnimator;
//=>
import com.nineoldandroids.animation.AnimatorInflater.loadAnimator;
  • res/animator/out_to_left.xml
    • XMLの書式自体はAndroid3系と同じ。これは凄く助かりますね
<?xml version="1.0" encoding="utf-8"?>
<set android:ordering="together">
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:valueType="floatType"
    android:propertyName="alpha"
    android:valueFrom="0"
    android:valueTo="500"
    android:duration="2000" />
</set>

set .. AnimatorSet に対応
objectAnimatorの記載に関しては従来通りでOK。

<?xml version="1.0" encoding="utf-8"?>
<set 
android:interpolator="@android:interpolator/decelerate_cubic"
android:ordering="together">
</set>

のように android:interpolator の設定も可能

参考URL)

 Android UI ICS本には 4系だとloadAnimatorが上手く動かない的な記載があるのですけど
NineOldAndroidだと動くのか、通常のでも4.1以上では動くのか
そこら辺は未検証・・

  • アニメーションのセット再生

旧)

int w = m_widthPixels;
final AnimationSet as = new AnimationSet(true);

//x方向に移動
TranslateAnimation hm = new TranslateAnimation(0, w, d(20), d(20));
hm.setDuration(600);

AlphaAnimation a = new AlphaAnimation(1.0f, 0.0f);
a.setDuration(600);

as.addAnimation(hm);
as.addAnimation(a);
as.setFillAfter(true);
as.startAnimation(view);

新)

AnimatorSet set = new AnimatorSet();
AnimatorSet as1 = new AnimatorSet();
as1
.playTogether(
		ObjectAnimator.ofFloat(view, "translationX", 0, w),
		ObjectAnimator.ofFloat(view, "translationY", d(20), d(20))
);
as1.setDuration(600);
/*
一応 
as1
.playTogether(
		ObjectAnimator.ofFloat(view, "translationX", 0, w).setDuration(600),
		ObjectAnimator.ofFloat(view, "translationY", d(20), d(20)).setDuration(600)
);
な書き方もかけますが再生時間が違う場合でない限りあまり意味が無いような(汗
*/

		
AnimatorSet as2 = new AnimatorSet();
Builder builder =as2.play(
		ObjectAnimator.ofFloat(view, "alpha", 1.0f, 0.0f)
);
// builder は before/after/with という形で使う
// 上記の例の場合は playTogether でもOK

as2.setDuration(600);
/*
もしくは
ObjectAnimator as2 = ObjectAnimator.ofFloat(view, "alpha", 1.0f, 0.0f).setDuration(600);
*/

		
//a1 => a2 の順
set.playSequentially(as1,as2);
set.start();
  • playSequentially / playTogeter は AnimatorSet/ObjectAnimator/ValueAnimator等 引数に混ぜてもOKなので凄い楽。
  • アニメーションリスナー

旧)

RotateAnimation
	setAnimationListener( new AnimationListener() {
		@Override
		public void onAnimationEnd(Animation animation) {
		}
 
		@Override
		public void onAnimationRepeat(Animation animation) {
		}
		
		@Override
		public void onAnimationStart(Animation animation) {
		}
	});


新)

ObjectAnimator animator
	animator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {

		}
	});


ValueAnimator animator
	animator.addUpdateListener(new AnimatorUpdateListener() {
                @Override
		public void onAnimationUpdate(ValueAnimator animation) {

		}
	});


AnimatorSet as = new AnimatorSet();
	as.addListener(new AnimatorListener(){
		@Override
		public void onAnimationCancel(Animator arg0) {
		
		}
		@Override
		public void onAnimationRepeat(Animator arg0) {
						
		}

		@Override
		public void onAnimationStart(Animator arg0) {
						
		}

		@Override
		public void onAnimationEnd(Animator arg0) {
		}
	});




アニメーションのパターンを指定)

旧)
Interpolator系

	Animation anim = new AlphaAnimation(1, 0);
	anim.setDuration(500);
	anim.setInterpolator(new CycleInterpolator(3));//繰り返し3指定
	v.startAnimation(anim);

	ObjectAnimator obj = ObjectAnimator.ofFloat(v, "alpha", 1, 0).setDuration(500);
	obj.setInterpolator(new CycleInterpolator(3));//繰り返し3指定
	obj.start();

参考)
Androidで動く携帯Javaアプリ作成入門(20):Androidアプリで“アニメーション”するための基礎知識 (3/3) - @IT
Androidのあ~ん |Animation その5 アニメーション分割処理パターン
Interpolatorの数値のみ利用をする。 - 素人のアンドロイドアプリ開発日記

使うとしたら、
 数値加算アニメーションとかで使うのかな?

新)
TypeEvaluator系

            ValueAnimator colorAnim = ObjectAnimator.ofInt(this, "backgroundColor", RED, BLUE);
            colorAnim.setDuration(3000);
            colorAnim.setEvaluator(new ArgbEvaluator()); //◎
            colorAnim.setRepeatCount(ValueAnimator.INFINITE);
            colorAnim.setRepeatMode(ValueAnimator.REVERSE);
            colorAnim.start();
フラグ値 説明
ValueAnimator.INFINITE 無限(回数)再生
ValueAnimator.REVERSE 逆再生
ValueAnimator.RESTART 再生終了後、最初から

ArgbEvaluator はRGBの変位計算するアニメパターン






IOSのような3D回転アニメ系)

Activityでやると、低端末では重いので
ViewFlipperで頑張ろうとしたが、下記みたいな感じ

Listener自体は下記の方法で設定可能とのこと

 viewFlipper.getInAnimation().setAnimationListener(new Animation.AnimationListener() {
      public void onAnimationStart(Animation animation) {}
      public void onAnimationRepeat(Animation animation) {}
      public void onAnimationEnd(Animation animation) {}
});


viewFlipper & アニメ遷移の情報は)

その他の回転アニメメモは)

A)縦回転>


B)横回転>


今回はまずA)で試す。
ただ横画面でこれを指定すると左右回転になってしまう・・・ ということで別途似たの作るイメージ


指定は)

	int mode =0;

	viewFlipper.setInAnimation(AnimationUtils.loadAnimation(game_main.instance, R.anim.down_land_in));
	viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(game_main.instance, R.anim.down_land_out));
	viewFlipper.setDisplayedChild(mode);
	//ちゃんと変わっていることを確認するなら setDisplayedChild前後で viewFlipper.getDisplayedChild()で確認

縦版>

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
        android:startOffset="200"
        android:duration="200"
        android:fromXScale="1.0"
        android:toXScale="0.0"
        android:fromYScale="1.0"
        android:toYScale="0.9"
        android:pivotX="50%"
        android:pivotY="50%"
/>
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="200"
        android:fromXScale="0.0"
        android:toXScale="1.0"
        android:fromYScale="0.9"
        android:toYScale="1.0"
        android:pivotX="50%"
        android:pivotY="50%"
/>
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
        android:startOffset="200"
        android:duration="200"
        android:fromXScale="0.0"
        android:toXScale="1.0"
        android:fromYScale="0.9"
        android:toYScale="1.0"
        android:pivotX="50%"
        android:pivotY="50%"
/>
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="200"
        android:fromXScale="1.0"
        android:toXScale="0.0"
        android:fromYScale="1.0"
        android:toYScale="0.9"
        android:pivotX="50%"
        android:pivotY="50%"
/>

横板>

  • down_land_in.xml
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
        android:startOffset="200"
        android:duration="200"
        android:fromYScale="1.0"
        android:toYScale="0.0"
        android:fromXScale="1.0"
        android:toXScale="0.9"
        android:pivotX="50%"
        android:pivotY="50%"
/>
  • down_land_out.xml
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="200"
        android:fromYScale="0.0"
        android:toYScale="1.0"
        android:fromXScale="0.9"
        android:toXScale="1.0"
        android:pivotX="50%"
        android:pivotY="50%"
/>
  • up_land_in.xml
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
        android:startOffset="200"
        android:duration="200"
        android:fromYScale="0.0"
        android:toYScale="1.0"
        android:fromXScale="0.9"
        android:toXScale="1.0"
        android:pivotX="50%"
        android:pivotY="50%"
/>
  • up_land_out.xml
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="200"
        android:fromYScale="1.0"
        android:toYScale="0.0"
        android:fromXScale="1.0"
        android:toXScale="0.9"
        android:pivotX="50%"
        android:pivotY="50%"
/>


備考)ViewFlipper挙動メモ)

  • layout-land にレイアウト置いてると読込エラーになるよ?


参考図書

Androidプログラミング上達読本

Androidプログラミング上達読本

Android UI Cookbook for 4.0 ICS(Ice Cream Sandwich)アプリ開発術

Android UI Cookbook for 4.0 ICS(Ice Cream Sandwich)アプリ開発術

Androidタブレットアプリ開発ガイド Android SDK 3対応 (Smart Mobile Developer)

Androidタブレットアプリ開発ガイド Android SDK 3対応 (Smart Mobile Developer)

  • 作者: 井形圭介,上中正統,尾古豊明,加藤勝也,小林慎治,瀬戸健二,高木基成,日高正博,夜子まま
  • 出版社/メーカー: 翔泳社
  • 発売日: 2011/09/16
  • メディア: 大型本
  • 購入: 4人 クリック: 156回
  • この商品を含むブログ (7件) を見る




TL上のメモ:NineOldAndroid)

eclipseの保管の設定は特に参考になる


[Java] - [Editor] - [Content Assist] - [Favorites]の[New Type...]


com.nineoldandroids.animation.Animator
com.nineoldandroids.animation.Animator.AnimatorListener
com.nineoldandroids.animation.AnimatorSet
com.nineoldandroids.animation.ObjectAnimator
com.nineoldandroids.view.ViewPropertyAnimator
あたりを確かに設定すると楽かも



TL上のメモ)

有名な開発者の id:sakura_bird1 さんでも悩まれているみたいで
アニメーション効果って皆さん悩まれているみたいだな。。*1 *2

[http://twitter.com/kimukou2628/status/299177170222325762:twitter:tree]


@ さんのgifアニメーションの話は



追記)

TLメモのやつは

の話を組み合わせれば、わざわざImageViewオーバライドしてやる必要ないですね(汗。

public class HogeImage extends ImageView {
	private Bitmap image

	@Override
	protected void onDraw(Canvas c) {
		super.onDraw(c);

		//〜 中略〜
		c.drawBitmap(image, 0, 0, null);
	}
}

なイメージを想定していました。

勿論

のような Canvas.save()/Canvas.restore() が必要なレベルのアニメだとこっちのほうが楽かもしれない


あとは ValueAnimator使うとか・・(下記みたいなイメージ)。

	ValueAnimator animator = ValueAnimator.ofFloat(0,5);
	animator.setDuration(5000);

	animator.addUpdateListner(new AnimatorUpdateListener() {
		@Override
		public void onAnimationUpdate(ValueAnimator animation) {
			//アニメーション経過時間(ミリ秒)
			long currentPlayTime( = animation.getCurrentPlayTime();
			//アニメーション経過割合(0-1.0)
			float animatatedFraction = animation.getAnimatatedFraction);
			//アニメーション値
			float animatatedValue = animation.getAnimatatedValue();

			//実際のアニメーション処理
        	}
	});
	animator.start();



追記2)
IOS7の縦Swipeの要望があって調べてたら出てきたメモ

iOS8がでたらまた違う要望が出てくるんだろうなー(遠い目

*1:自分はどちらかというとIOSに似せてというオーダで悩んでるわけですが<汗

*2:Androidらしいデザイン、Androidらしいアニメーションというレベルが高い悩みじゃないのが厳しい<汗

*3:何時も探すのでメモっておく