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>
おまけ: デフォルト設定