2014年12月4日木曜日

Android Activity Transitions を実装する

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

1. window content transitions を有効にする

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

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


2. transition を指定する

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

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

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


3. ActivityOptions を指定して実行

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


Fade


Slide




4. sharedElement を指定する

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

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

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

遷移前(activity_main.xml)
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     ...>  
  6.   
  7.     <ImageView  
  8.         android:id="@+id/image"  
  9.         android:layout_width="match_parent"  
  10.         android:layout_height="wrap_content"  
  11.         android:background="#cccccc"  
  12.         android:src="@drawable/ic_launcher"  
  13.         android:transitionName="image" />  
  14.   
  15.     <Button  
  16.         android:id="@+id/button"  
  17.         android:layout_width="match_parent"  
  18.         android:layout_height="wrap_content"  
  19.         android:layout_alignParentBottom="true"  
  20.         android:text="go to SubActivity" />  
  21.   
  22. </RelativeLayout>  
遷移後(activity_sub.xml)
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     ...>  
  6.   
  7.     <ImageView  
  8.         android:id="@+id/image"  
  9.         android:layout_width="match_parent"  
  10.         android:layout_height="200dp"  
  11.         android:background="#cccccc"  
  12.         android:src="@drawable/gopher"  
  13.         android:transitionName="image" />  
  14.   
  15. </RelativeLayout>  
* わかりやすさのために、遷移前後の ImageView の画像を変えています。


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





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


5. 複数の sharedElement を指定する

複数の View を共通のエレメントとして指定することができます。
  1. public class MainActivity extends Activity {  
  2.   
  3.     ...  
  4.   
  5.     private void gotoSub() {  
  6.         ImageView iv = (ImageView) findViewById(R.id.image);  
  7.         String sharedElementName = "image";  
  8.         iv.setTransitionName(sharedElementName);  
  9.   
  10.         ImageView iv2 = (ImageView) findViewById(R.id.image2);  
  11.         String sharedElementName2 = "image2";  
  12.         iv2.setTransitionName(sharedElementName2);  
  13.   
  14.         Intent intent = new Intent(this, SubActivity.class);  
  15.         startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this,  
  16.                 new Pair<View, String>(iv, sharedElementName),  
  17.                 new Pair<View, String>(iv2, sharedElementName2))  
  18.                 .toBundle());  
  19.     }  
  20. }  
  1. public class SubActivity extends Activity {  
  2.   
  3.     @Override  
  4.     protected void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         setContentView(R.layout.activity_sub);  
  7.   
  8.         String sharedElementName = "image";  
  9.         findViewById(R.id.image).setTransitionName(sharedElementName);  
  10.   
  11.         String sharedElementName2 = "image2";  
  12.         findViewById(R.id.image2).setTransitionName(sharedElementName2);  
  13.     }  
  14. }  





6. sharedElement の transition を指定する

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

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

テーマで指定する場合
  1. <style name="BaseAppTheme" parent="android:Theme.Material">  
  2.   ...  
  3.   <item name="android:windowSharedElementEnterTransition">@transition/custom</item>  
  4.   <item name="android:windowSharedElementExitTransition">@transition/custom</item>  
  5. </style>  
sharedElement のデフォルトの transition は Theme.Material で指定されており、@android:transition/move になっています。
このファイルの中身は次のようになっています。

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

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

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






おまけ: デフォルト設定

  1. <style name="Theme.Material">  
  2.     <item name="windowContentTransitions">false</item>  
  3.     <item name="windowEnterTransition">@transition/fade</item>  
  4.     <item name="windowSharedElementEnterTransition">@transition/move</item>  
  5.     <item name="windowSharedElementExitTransition">@transition/move</item>  
  6.     ...  
  7. </style>  
  8.   
  9. <style name="Theme.Material.Light" parent="Theme.Light">  
  10.     <item name="windowContentTransitions">false</item>  
  11.     <item name="windowEnterTransition">@transition/fade</item>  
  12.     <item name="windowSharedElementEnterTransition">@transition/move</item>  
  13.     <item name="windowSharedElementExitTransition">@transition/move</item>  
  14.     ...  
  15. </style>  

0 件のコメント:

コメントを投稿