はじめに
お久しぶりです、シオンです。
久しぶりにAndroidのアプリ開発をしていて詰まったので解決方法を共有したいと思います。
Google I/O 2018にてMaterial Designが刷新され、それに伴いMaterial.ioのガイドもかなり変わりました。
そんな中、コンポーネントのCardsに次のようなアニメーションがありました。
かっこいい、、やりたい、、、!
と思いましたがこの画像を保ったまま遷移するのはどのように実装するのか、詰まっていました。
そもそもアニメーションの名前すらわからない
Google曰く、
A card expands to fill the full screen using a parent-child transition.
親子遷移を使い、カードをフルスクリーンに展開する。
いや、意味がわからない。
仕方がないので、自分で調べていくなかで、それっぽい名前を見つけました。
Shared Element Transition と言うらしい。
共通要素を使った遷移、まさにこれです
ということで本記事では、この遷移を使い
さきほどの画像のようなアニメーションを実装していこうと思います。
サンプルコードはGithubにあります
実装
準備
Material Componentsを使用したいため、最新のサポートライブラリを追加します。
dependencies {
...
implementation 'com.android.support:design:28.0.0-alpha3'
implementation 'com.android.support:appcompat-v7:28.0.0-alpha3'
}
遷移元のActivityを作る
遷移元となるActivityを作ります。
先ほどのアニメーションでいうところの、この画面です。
MaterialCardView
を使いできるだけ寄せていきます。
僕は楽なのでLinerLayoutを使っています。
(もっといい書き方があると思うのでプルリクやコメントくれると嬉しいです)
<android.support.design.card.MaterialCardView
android:id="@+id/user_cardView"
android:layout_width="match_parent"
android:layout_height="266dp"
app:cardCornerRadius="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="@+id/header_imageView"
android:layout_width="match_parent"
android:layout_height="194dp"
android:scaleType="centerCrop"
app:srcCompat="@drawable/header" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_margin="16dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/icon_imageView"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginRight="16dp"
android:layout_weight="1"
app:srcCompat="@drawable/icon" />
<LinearLayout
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/user_name_textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/user_name"
android:textColor="@color/colorHeaderText"
android:textSize="20dp"
android:textStyle="bold" />
<TextView
android:id="@+id/user_profession_textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/user_profession"
android:textColor="@color/colorSubheadText"
android:textSize="14dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</android.support.design.card.MaterialCardView>
実際の画面はこんな感じです。
遷移先のActivityを作る
次に遷移先となるActivityを作ります。
この画面です。
先ほどのレイアウトを元に作りました。
実装した画面はこんな感じです。
共通要素を設定する
遷移元と遷移先でシェアをする共通の要素を設定します。
指定方法は、layoutファイルにtransitionName
で指定します。
transitionName
は、遷移元、遷移先でそれぞれ共通となるようする必要があります。
今回は、MainActivityからUserActivityへの遷移です。
共通の要素は、以下の4つです。それぞれに同じtransitionName
を指定します。
-
Header Image
transionName : userHeader -
User Icon
transionName : userIcon -
User Name
transionName : userName -
User Profession
transionName : userProfession
このように指定することで、共通の要素として扱うことができます。
例えば、ユーザーのヘッダー画像に対しては、次のように指定します。
...
<ImageView
android:id="@+id/header_imageView"
...
android:transitionName="userHeader"
...
/>
...
遷移先のヘッダー画像に対しても同様に指定します。
<ImageView
android:id="@+id/user_header_imageView"
...
android:transitionName="userHeader"
...
/>
これにより、遷移元と遷移先の各パーツを共通の要素として扱う準備ができました。
次にこの設定を元に遷移する処理を書いていきます。
Activityを遷移する
遷移元のActivityにて、共通の要素を取得します。
userHeader = (ImageView) findViewById(R.id.header_imageView);
userIcon = (ImageView) findViewById(R.id.icon_imageView);
userName = (TextView) findViewById(R.id.name_textView);
userProfession = (TextView) findViewById(R.id.profession_textView);
CardView
にOnClickListener
を使いクリックされたときの処理を書いていきます。
まず、共通の要素とtransitionName
よりペアを作成します。
ヘッダー画像の場合は次のようにペアを作成します。
Pair.create((View) userHeader, "userHeader")
作成したペアを、遷移時のオプションとして設定します。
ActivityOptions options = ActivityOptions.
makeSceneTransitionAnimation(MainActivity.this,
Pair.create((View) userHeader, "userHeader")
);
このオプションをstartActivity
にBundle
として与えることで
Shared Element Transition を行うことができます!
Intent intent = new Intent(MainActivity.this, UserActivity.class);
startActivity(intent, options.toBundle());
カードをクリックしたときの最終的な処理は次のようになりました。
...
@Override
public void onClick(View view) {
ActivityOptions options = ActivityOptions.
makeSceneTransitionAnimation(MainActivity.this,
Pair.create((View) userHeader, "userHeader"),
Pair.create((View) userIcon, "userIcon"),
Pair.create((View) userName, "userName"),
Pair.create((View) userProfession, "userProfession")
);
Intent intent = new Intent(MainActivity.this, UserActivity.class);
startActivity(intent, options.toBundle());
}
まとめ
最終的のこのようなアニメーションになりました!
色々、使い道が浮かんできます。
サンプルコードはGithubにあるので、指摘事項はコメントやIssueなどでください
shion1118/CardTransition - Github
最後まで読んでいただき
ありがとうございました