今更ながらActivity Transitions
Android Developersを読みながら,Activity Transitionsを実装しました.
やったことを書きます.
手順
やったことは大きく分けて3つでした.
- Activity Transitions用のテーマの作成
- 2つのActivityで共有するViewを決める
- startActivityをActivity Transitons用に書き換える
ActivityTransitions用のテーマの作成
今のテーマはこうなってます.
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/primary</item>
<!-- 省略 -->
</style>
それをこうしておきます.
<style name="AppTheme" parent="AppTheme.Base" />
<style name="AppTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/primary</item>
<!-- 省略 -->
</style>
AppThemeにあった内容を,新しく作ったAppTheme.Baseに移しました.
ActivityTransitionsに必要な属性は,minSdkVersionが21以上でないと使えません.
minSdkVersionは変えたくないので,res/values-v21/styles.xml
で属性の追加を行います.
res/values-v21/styles.xml
を作成し,以下の内容を書きます.
<style name="AppTheme" parent="AppTheme.Base"> <!-- AppTheme.Baseを継承 -->
<item name="android:windowContentTransitions">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>
<item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
<item name="android:windowSharedElementExitTransition">@android:transition/move</item>
</style>
AppTheme.Baseを作ったのは,ここで余計なコードを書かないためです.
そして,遷移を行う2つのアクティビティImageListActivity
とImageDetailActivity
に,
このテーマを適用します.
<activity
android:name=".ui.ImageListActivity"
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ui.ImageDetailActivity"
android:theme="@style/AppTheme" />
これで,テーマの設定は完了です.
2つのActivityで共有するViewを決める
リストから詳細画面への遷移なので,クリックした画像(ImageView
)を共有することにします.
変更するのは,共有するViewを定義している2つのレイアウトファイルです.
こちらも,minSdkVersionが21より小さいアプリでも対応できるよう,
res/layout-v21というディレクトリを作って,そちらに変更を行ったファイルを置いていきます.
具体的には,
res/layout/row_list.xml
は,res/layout-v21/row_list.xml
にコピーして,res/layout-v21/row_list.xml
の方で変更を行います.
では,res/layout-v21
にコピーした,リストのlayout定義ファイルのImageViewに変更を加えます.
ListViewのArrayAdapterの中で,このように使っているレイアウトファイルのことです.
convertView = mInflater.inflate(R.layout.row_list, parent, false);
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/row_parent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/row_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:transitionName="@string/trans_name" /> <!-- new line -->
<!-- 省略 -->
android:transitionName="@string/trans_name"
を共有したいImageViewの属性に追加しました.
@string/trans_name
は下のように定義した,ただの文字列です.
<string name="trans_name">list_to_detail</string>
詳細画面のレイアウトファイルでも同じことをします.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/detail_parent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/detail_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:transitionName="@string/trans_name" /> <!-- new line -->
<!-- 省略 -->
android:transitionName="@string/trans_name"
を共有したいImageViewの属性に追加しました.
このandroid:transitionName
によって,
リストの画像は詳細画面のどこに移動すれば良いのか分かるようになります.
あとは,startActivityの部分を書き換えれば完成です.
startActivityをActivityTransitions用に書き換える
リストのクリックに合わせて詳細画面に行く部分はこんな感じでした.
mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ListItem item = mAdapter.getItem(position);
Intent intent = new Intent(mActivity, ImageDetailActivity.class);
intent.putExtra(ImageDetailActivity.EXTRA_CONTENT, item.toJson());
startActivity(intent);
}
});
それがこうなります.
mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(
mActivity,
view.findViewById(R.id.row_image),
getString(R.string.trans_name) );
ListItem item = mAdapter.getItem(position);
Intent intent = new Intent(mActivity, ImageDetailActivity.class);
intent.putExtra(ImageDetailActivity.EXTRA_CONTENT, item.toJson());
ActivityCompat.startActivity(activity, intent, options.toBundle());
}
});
これで完成です.
##最後に
GitHubにあった,MaterialEverywhereとMaterialDesignSampleが,とても参考になりました.