woshidan's blog

そんなことよりコードにダイブ。

Androidのアニメーションを色々作ってみる

アニメーションに苦手意識があったので、アニメーションのAPIを叩いてみました。

1つ2つならコールバックでいけますが、もっとたくさんのアニメーションを逐次連続して実行したい場合などは、http://language-and-engineering.github.io/android-mvc-framework/ を見るとよいらしいです。

内容

  • ViewCompatを使う
  • Drawable Animationを使う
  • Tween Animationを使う

ViewCompatを使う

参考:

ViewCompat | Android Developers

TextInputLayoutのソースコードを見ていたら、ViewCompatを使ってViewの透明度やサイズ等を、変更にかける時間等と合わせていじれるそうで、試してみた。

消えるとき、ちょっと上の方へ消えて欲しいとか、透明度をすいっと変化して欲しいとか、それくらいの簡単なアニメーションならこれが便利ではと思ったけど、同種のアニメーションを使い回したい場合はやっぱりTweenの方を使ってxmlのリソースを各所から呼び出す方がいいんだろうか。

1つのアニメーションするカスタムビューを作って使い回すならこれがよさそう。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <TextView
        android:id="@+id/text_view"
        android:text="Anim by ViewCompat"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/button"
        android:text="push"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
</LinearLayout>
public class MainActivity extends AppCompatActivity {
    private boolean TEXT_VISIBILITY = true;
    private int ANIMATION_DURATION = 1000;
    static final Interpolator FAST_OUT_SLOW_IN_INTERPOLATOR = new FastOutSlowInInterpolator();
    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTextView = (TextView) findViewById(R.id.text_view);
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (TEXT_VISIBILITY) {
                    TEXT_VISIBILITY = false;
                    ViewCompat.animate(mTextView)
                            .alpha(0f) // 透明度0へ向かってアニメーション
                            .translationY(-16) // 上の方へ消えていく
                            .scaleX(2f) // 透明になった時のサイズ
                            .setDuration(ANIMATION_DURATION)
                            .setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR)
                            .setListener(new ViewPropertyAnimatorListenerAdapter(){
                                // 設定したアニメーションが終わったら非表示に
                                @Override
                                public void  onAnimationEnd(View view) {
                                    view.setVisibility(View.INVISIBLE);
                                }
                            })
                            .start();
                } else {
                    TEXT_VISIBILITY = true;
                    ViewCompat.animate(mTextView)
                            .alpha(1f)
                            .translationY(0)
                            .scaleX(0.5f) // 表示された時の倍率
                            .setDuration(ANIMATION_DURATION)
                            .setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR)
                            .setListener(new ViewPropertyAnimatorListenerAdapter(){
                                // 設定したアニメーションが始まる際に表示状態に
                                @Override
                                public void  onAnimationStart(View view) {
                                    view.setVisibility(View.VISIBLE);
                                }
                            })
                            .start();
                }
            }
        });
    }

f:id:woshidan:20151115220955g:plain

Tween Animationを使う

参考:

Viewにアニメーションを付与する(Tweenアニメーション) « Tech Booster

res/animにxmlを書いてアニメーションを作るTweenアニメーション。Animation#setFillAfter(true)でアニメーション終了後のα値や相対移動値を保持できるみたいです。

public class MainActivity extends AppCompatActivity {
    private boolean TEXT_VISIBILITY = true;
    private TextView mTextView;
    private Animation anim_start;
    private Animation anim_end;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTextView = (TextView) findViewById(R.id.text_view);
        Button button = (Button) findViewById(R.id.button);
        anim_start = AnimationUtils.loadAnimation(this, R.anim.anim_start);
        anim_end = AnimationUtils.loadAnimation(this, R.anim.anim_end);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (TEXT_VISIBILITY) {
                    TEXT_VISIBILITY = false;
                    mTextView.startAnimation(anim_start);
                    mTextView.setVisibility(View.VISIBLE);
                } else {
                    TEXT_VISIBILITY = true;
                    mTextView.startAnimation(anim_end);
                    mTextView.setVisibility(View.INVISIBLE);
                }
            }
        });
<!-- anim_start -->
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:interpolator="@android:anim/accelerate_interpolator">
    <alpha
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />
    <translate
        android:fromYDelta="16"
        android:toYDelta="0"
        />
</set>
<!-- anim_end -->
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:interpolator="@android:anim/accelerate_interpolator">
    <alpha
        android:fromAlpha="1.0"
        android:toAlpha="0.0" />
</set>

f:id:woshidan:20151115221026g:plain

Drawable Animationを使う

参考:

AnimationDrawableでアニメーションを作る « Tech Booster

drawableに画像ファイルを入れてパラパラアニメを作ります。

今回は画像が無いので色違いのshapeで対応しようと思ったらできなかったので、TweenAnimationの時のアニメのコマを切り取ってをひたすら回してみた。

animation-listxmlres/animではなく、res/drawable以下に置く必要があるので注意です。

<!-- drawableフォルダに置く -->
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
    <item android:drawable="@drawable/anim1" android:duration="50" />
    <item android:drawable="@drawable/anim2" android:duration="50" />
    <item android:drawable="@drawable/anim3" android:duration="50" />
    <item android:drawable="@drawable/anim4" android:duration="50" />
    <item android:drawable="@drawable/anim5" android:duration="50" />
    <item android:drawable="@drawable/anim6" android:duration="50" />
</animation-list>
public class MainActivity extends AppCompatActivity {
    private boolean TEXT_VISIBILITY = true;
    private TextView mTextView;
    private AnimationDrawable mFrameAnimation;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);

        mTextView = (TextView) findViewById(R.id.text_view);
        mTextView.setBackgroundResource(R.drawable.animation_list);
        Button button = (Button) findViewById(R.id.button);

        // AnimationDrawableを取得
        mFrameAnimation = (AnimationDrawable) mTextView.getBackground();

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // アニメーションの開始
                mFrameAnimation.start();
            }
        });
    }

f:id:woshidan:20151115221103g:plain