2014年12月4日木曜日

Android Activity Transitions を実装する

Activity Transitions のドキュメントを読んだのですが、よくわからなかったので実際に試してみました。

1. window content transitions を有効にする

Activity Transitions を使うには、window content transitions を有効にする必要があります。

コードで有効にする場合 getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); テーマで有効にする場合 <style name="BaseAppTheme" parent="android:Theme.Material"> <item name="android:windowContentTransitions">true</item> </style>

2. transition を指定する

切り替え時のアニメーションを指定します。用意されているクラスは Explode, Fade, Slide です。
自分で transition を作るときは、これらの親クラスの Visibility を継承するのがよさそうです。

コードで指定する場合 getWindow().setExitTransition(new Explode()); Explode, Fade, Slide に対応するリソースは
@android:transition/explode
@android:transition/fade
@android:transition/slide
です。

テーマで指定する場合 <style name="BaseAppTheme" parent="android:Theme.Material"> <item name="android:windowEnterTransition">@android:transition/explode</item> <item name="android:windowExitTransition">@android:transition/explode</item> </style>

3. ActivityOptions を指定して実行

ActivityOptions.makeSceneTransitionAnimation() を使います。
Android Developers のドキュメントでは、引数に this しか渡していませんが、引数が1つのメソッドはありません!(2014年12月4日現在)
次のように第2引数に null を指定します。 startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this, null).toBundle()); 全体としてこんな感じになります。 public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); getWindow().setExitTransition(new Explode()); setContentView(R.layout.activity_main); findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { gotoSub(); } }); } private void gotoSub() { Intent intent = new Intent(this, SubActivity.class); startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this, null).toBundle()); } } Explode


Fade


Slide




4. sharedElement を指定する

遷移前の画面の一部が拡大などして、遷移後の画面の一部になるような transition が可能です。
そのためには、どの View が共通として見なせるのか指定する必要があります。

遷移前後両方のActivityで、一意の名前を指定します。
レイアウトで指定する場合は android:transitionName を使います。

以下では、それぞれの Activity のレイアウトで ImageView に android:transitionName="image" を指定しています。

遷移前(activity_main.xml) <RelativeLayout 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" ...> <ImageView android:id="@+id/image" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#cccccc" android:src="@drawable/ic_launcher" android:transitionName="image" /> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:text="go to SubActivity" /> </RelativeLayout> 遷移後(activity_sub.xml) <RelativeLayout 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" ...> <ImageView android:id="@+id/image" android:layout_width="match_parent" android:layout_height="200dp" android:background="#cccccc" android:src="@drawable/gopher" android:transitionName="image" /> </RelativeLayout> * わかりやすさのために、遷移前後の ImageView の画像を変えています。


android:transitionName に指定した名前を makeSceneTransitionAnimation() でも指定する必要があります。 public class MainActivity extends Activity { ... private void gotoSub() { ImageView iv = (ImageView) findViewById(R.id.image); Intent intent = new Intent(this, SubActivity.class); startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this, iv, "image").toBundle()); } }




android:transitionName を使わずにコードで指定することもできます。 public class MainActivity extends Activity { ... private void gotoSub() { ImageView iv = (ImageView) findViewById(R.id.image); String sharedElementName = "image"; iv.setTransitionName(sharedElementName); Intent intent = new Intent(this, SubActivity.class); startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this, iv, sharedElementName) .toBundle()); } } public class SubActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sub); String sharedElementName = "image"; findViewById(R.id.image).setTransitionName(sharedElementName); } }

5. 複数の sharedElement を指定する

複数の View を共通のエレメントとして指定することができます。 public class MainActivity extends Activity { ... private void gotoSub() { ImageView iv = (ImageView) findViewById(R.id.image); String sharedElementName = "image"; iv.setTransitionName(sharedElementName); ImageView iv2 = (ImageView) findViewById(R.id.image2); String sharedElementName2 = "image2"; iv2.setTransitionName(sharedElementName2); Intent intent = new Intent(this, SubActivity.class); startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this, new Pair<View, String>(iv, sharedElementName), new Pair<View, String>(iv2, sharedElementName2)) .toBundle()); } } public class SubActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sub); String sharedElementName = "image"; findViewById(R.id.image).setTransitionName(sharedElementName); String sharedElementName2 = "image2"; findViewById(R.id.image2).setTransitionName(sharedElementName2); } }




6. sharedElement の transition を指定する

sharedElement の transition は setSharedElementEnterTransition()setSharedElementExitTransition() で指定します。その他の transition には setExitTransition() や setEnterTransition() で指定したものが適用されます。

コードで指定する場合 Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.custom); getWindow().setSharedElementExitTransition(transition); getWindow().setSharedElementEnterTransition(transition); XMLで用意した transition リソースから Transition オブジェクトを作るには TransitionInflater を使います。

テーマで指定する場合 sharedElement のデフォルトの transition は Theme.Material で指定されており、@android:transition/move になっています。
このファイルの中身は次のようになっています。

@android:transition/move <transitionSet xmlns:android="http://schemas.android.com/apk/res/android"> <changeBounds/> <changeTransform/> <changeClipBounds/> <changeImageTransform/> </transitionSet> changeBounds は View の大きさをアニメーションさせ、changeImageTransform は ImageView にセットされている画像サイズをアニメーションさせます。

transition リソースの書き方は Transition クラスに概要があります。

例えば、@android:transition/move の <transitionSet> に android:transitionOrdering="sequential" を指定すると、各アニメーションが順番に行われます。
res/transition/custom.xml <?xml version="1.0" encoding="utf-8"?> <transitionSet xmlns:android="http://schemas.android.com/apk/res/android" android:transitionOrdering="sequential"> <changeBounds /> <changeTransform /> <changeClipBounds /> <changeImageTransform /> </transitionSet>





おまけ: デフォルト設定

1 件のコメント:

  1. Can you write a blog post about error handling exception for API Calls.. and should contains UI. Like how we get in google apps.. when there is no interest . they show a text and a button (retry).

    返信削除