251
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

Activity/Fragment Transitionsのつかいかた

Android Advent Calendar 2014 21日目の記事です。

LollipopでActivity Transitionsが追加されました。(https://developer.android.com/training/material/animations.html#Transitions)
Fragmentにも無いのかな?と探してみたところ普通にありましたので,あわせて新たに追加されたTransitionの使い方をまとめます。

できるようになったこと

今まではActivity/Fragmentの遷移時のアニメーションについては、それぞれの持つView 全体 に対して効果を指定していました。
LollipopからはTransitionを用いることにより、Activity/Fragmentの 各View についてアニメーション可能になりました。
例えばViewが画面外に発散したり、Viewを共有させたまま画面遷移するといったアニメーションです。

Transition

android.transitionはKitKatにて追加されたパッケージで、UIの異なる2つの状態について遷移アニメーションを自動的に行ってくれます。
以下では用意されているもののうち6つを紹介します。

Expode

収束・発散します
explode.gif

Fade

フェードイン・フェードアウトします。
fade.gif

Slide

スライドイン・スライドアウトします。
setSlideEdge(int slideEdge)でスライドする方向が指定出来ます。

Slide
Slide slide = new Slide();
slide.setSlideEdge(Gravity.RIGHT);

slide.gif

ChangeBounds

Viewの位置・大きさが変わるようなTransitionです。

ChangeImageTransform

ImageViewのmatrixが変化するようなTransitionです。
ChangeBoundsと一緒に使うことで位置・大きさ・スケールがスムーズに変化します。
image.gif

TransitionSet

他のTransitionをまとめます。setOrdering(int ordering)にて順番に処理するか同時に処理するかを設定出来ます。

Transition
TransitionSet set = new TransitionSet();
set.addTransition(new ChangeBounds());
set.addTransition(new ChangeImageTransform());
//順番にTransitionを実行する
set.setOrdering(TransitionSet.ORDERING_SEQUENTIAL);

Activity/Fragment Transitions実装の流れ

TransicionをActivityやFragmentの遷移に使うためには、以下のように記述します。

  1. window contentのTransitionの有効化
  2. Transitionの定義
  3. Activity/FragmentにTransitionの設定
  4. SharedElementの設定
  5. Activity/Fragmentの起動

ここからはFragment/Activityそれぞれについて使い方を説明していきます。

Fragment Trnasitions

1. window contentのTransitionの有効化

コードまたはxmlでwindow contentのTransitionを有効にします。

getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
style.xml
<resources>
    <style name="Theme.Base" parent="android:Theme.Material.Light">
        <item name="android:windowContentTransitions">true</item>
    </style>
</resources>

2. Transitionの定義

コードまたはxmlで遷移する際に実行されるTransitionを定義します。

TransitionSet ts = new TransitionSet();
ts.addTransition(new Fade());
ts.addTransition(new Slide());
res/transition/base_transition.xml
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"  >
    <fade />
    <slide />
</transitionSet>

3. FragmentにTransitionの設定

FragmentにTransitionを設定しますが、以下のパターンがあります。遷移元をFROM,遷移先をTOとすると

ExitTransition

FROMからTOを呼び出した時、FROMのViewが消えるアニメーション

EnterTransition

FROMからTOを呼び出した時、TOのViewが現れるアニメーション

ReturnTransition

TOからFROMに戻る時、TOのViewが消えるアニメーション
デフォルトだとEnterTransitionと同じものが使われます

ReenterTransition

TOからFROMに戻る時、FROMのViewが現れるアニメーション
デフォルトだとExitTransitionと同じものが使われます

以上のパターンについてFragmentにsetterが存在するので、2.で定義したTransitionを設定します。

Fragment
Fragment frag = new NextFragment();
frag.setEnterTransition(ts);

xmlで記述も出来ます。

style.xml
<resources>
    <style name="Theme.Base" parent="android:Theme.Material.Light">
     <item name="android:fragmentEnterTransition">
              @transition/base_transition
         </item>
    </style>
</resources>

4. SharedElementの設定

Viewを共有するような形でシームレスに遷移させる場合はSharedElementを設定します。
その際にはSharedElement用にTransitionを設定し、遷移前後で共有するViewに同じTransitionNameをつけなければなりません。
SharedElementを利用しなければ以下の設定は必要ありません。

遷移元Fragment
//Transitionを設定する
Frag frag = new TransitionFragment();
frag.setEnterTransition(set);
frag.setSharedElementEnterTransition(set);

//共有するViewにTransitionNameをつける
View target = findViewById(R.id.sharedElement);
target.setTransitionName("share");

//SharedElementとして設定する
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.container,frag).addSharedElement(target, transitionName);

遷移先Fragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_next, container, false);
    View v = rootView.findViewById(R.id.sharedElement);
    v.setTransitionName("share");

    return rootView;
}

5. Fragmentの起動

あとは起動するだけです。まとめてみると

FragmentTransitionActivity.java
public class FragmentTransitionActivity extends Activity implements View.OnClickListener {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
        setContentView(R.layout.activity_main);
        if (savedInstanceState == null) {
            getFragmentManager().beginTransaction()
                    .add(R.id.container, new TransitionFragment())
                    .commit();
        }
    }

    @Override
    public void onClick(View v) {
        TransitionSet set = new TransitionSet();
        set.addTransition(new ChangeImageTransform());
        set.addTransition(new ChangeBounds());

        View target = v.findViewById(R.id.sharedElement);
        Fragment frag = new NextActivity.PlaceholderFragment();
        frag.setEnterTransition(set);
        frag.setSharedElementEnterTransition(set);
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.replace(R.id.container,frag )
                .addSharedElement(target, "share")
                .addToBackStack(null)
                .commit();
    }

    public static class TransitionFragment extends Fragment {
        @Override
        public View onCreateView (LayoutInflater inflater, ViewGroup container,
                                  Bundle savedInstanceState){
            View rootView = inflater.inflate(R.layout.fragment_main, container, false);
            View target = rootView.findViewById(R.id.sharedElement);
            target.setTransitionName("share");
            target.setOnClickListener((ForthActivity)getActivity());
            return rootView;
        }

    }
}


Activity Transitions

1. window contentのTransitionの有効化

Fragmentと同様に設定します。

2. Transitionの定義

Fragmentと同様に定義します。

3. ActivityにTransitionの設定

Activityの場合はWindowに対してTransitionを設定します。

getWindow().setExitTransition(ts);  
getWindow().setEnterTransition(ts); 

4. SharedElementの設定

Activityの場合は共有するViewに同じTransitionNameをつけ なくても いいみたいです。遷移先のViewにTransitionNameで設定しActivityOptions.makeSceneTransitionAnimation()で指定すればよさそうです。
SharedElementが1つの場合はそのままViewとTransitionNameを指定出来ますし、複数の場合はPairを使えます。

SharedElementを利用しない場合は、第2引数をnullにしてActivityOptionsを生成します。

遷移元Activity
//SharedElementを利用しない
ActivityOptions option0 = ActivityOptions.makeSceneTransitionAnimation(this, null);

//SharedElementが1つだけ
View target1 = findViewById(R.id.sharedElement1);
ActivityOptions options1 = 
    ActivityOptions.makeSceneTransitionAnimation(this, target1, "share");

//SharedElementが複数の場合
View target2 = findViewById(R.id.sharedElement2);
ActivityOptions options2 = ActivityOptions.makeSceneTransitionAnimation(this,  
                new Pair<View, String>(target1, "share1"),  
                new Pair<View, String>(target2, "share2")); 
遷移先Activity
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    View target1 = findViewById(R.id.sharedElement1);
    target1.setTransitionName("share1");
    View target2 = findViewById(R.id.sharedElement2);
    target2.setTransitionName("share2");
}

5. Activityの起動

4.で生成したActivityOptionsを利用して起動します。
まとめるとこんな感じ。

ActivityTransitionActivity.java
public class ActivityTransitionActivity extends Activity implements View.OnClickListener {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
        setContentView(R.layout.fragment_main);
        TransitionSet ts = new TransitionSet();
        ts.addTransition(new Fade());
        ts.addTransition(new Explode());
        getWindow().setExitTransition(ts);
        getWindow().setEnterTransition(ts);

        View v = findViewById(R.id.image);
        v.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        Intent intent = new Intent(this, NextActivity.class);
        View target = v.findViewById(R.id.image);
        ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, target, "share");
        startActivity(intent, options.toBundle());
    }
}                   

まとめ

Lollipopからは、Activity/Fragmentの遷移アニメーションについてより柔軟に設定が可能になりました。
特にSharedElementに関しては実装は簡単に行えるのにUI上の効果は大きいです。(Android Transisionsの通り従来の方法で実装しようとしましたが、断念。。)
実はAndroid studio 1.0のSampleに
ActivitySceneTransitionBasicがあるのでこれをImportして動かしてみるのが一番早いです。
よくあるMaster-Detail構成で、そのActivity遷移にTransitionを使っています。
SampleにFragment Transitionというのもありますがこれは本記事の内容とは違いTransitionでなくAnimationを使うサンプルなのでお気をつけ下さい。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
251
Help us understand the problem. What are the problem?