Activity Transitions の
ドキュメントを読んだのですが、よくわからなかったので実際に試してみました。
1. window content transitions を有効にする
Activity Transitions を使うには、window content transitions を有効にする必要があります。
コードで有効にする場合
- getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
テーマで有効にする場合
- <style name="BaseAppTheme" parent="android:Theme.Material">
- <item name="android:windowContentTransitions">true</item>
- </style>
<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());
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>
<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());
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());
- }
- }
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>
<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>
<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());
- }
- }
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 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);
- }
- }
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 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);
- }
- }
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);
Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.custom);
getWindow().setSharedElementExitTransition(transition);
getWindow().setSharedElementEnterTransition(transition);
XMLで用意した transition リソースから Transition オブジェクトを作るには
TransitionInflater を使います。
テーマで指定する場合
- <style name="BaseAppTheme" parent="android:Theme.Material">
- ...
- <item name="android:windowSharedElementEnterTransition">@transition/custom</item>
- <item name="android:windowSharedElementExitTransition">@transition/custom</item>
- </style>
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>
<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>
<?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>
おまけ: デフォルト設定
- <style name="Theme.Material">
- <item name="windowContentTransitions">false</item>
- <item name="windowEnterTransition">@transition/fade</item>
- <item name="windowSharedElementEnterTransition">@transition/move</item>
- <item name="windowSharedElementExitTransition">@transition/move</item>
- ...
- </style>
-
- <style name="Theme.Material.Light" parent="Theme.Light">
- <item name="windowContentTransitions">false</item>
- <item name="windowEnterTransition">@transition/fade</item>
- <item name="windowSharedElementEnterTransition">@transition/move</item>
- <item name="windowSharedElementExitTransition">@transition/move</item>
- ...
- </style>