3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Activity transitions+shared elementsで画面遷移にアニメーションつけてきた+詰まったところ

Last updated at Posted at 2019-07-11

今携わっているマッチングアプリで、ActivityTransactionで画面遷移をやってみました。

poi_transition_success.gif
※こちらはデモなので私が撮影した我が家のかわいいネコチャンが表示されています。実際のアプリではかわいい女性が表示されます。

要件

  • カード選択画面(左右スワイプで選ぶ)→プロフィール詳細への移動のとき、同じ写真はスムーズなアニメーションで地続きになるようにする
  • プロフィール詳細には複数写真があるので、プロフィール詳細で選んだ写真がそのままカード選択画面でも表示されるようにする

参考サイト

Android公式サイト
https://developer.android.com/training/transitions/start-activity
Googleデベロッパーブログ
https://developers-jp.googleblog.com/2018/04/continuous-shared-element-transitions.html

その他transition animationやらいろいろ検索ででてきたサイト

実装方法

カードからプロフィールへの遷移

SharedElementsを有効にする

style.xmlで定義してあるアプリのrootThemeに

<item name="android:windowActivityTransitions">true</item>
<item name="android:windowSharedElementsUseOverlay">true</item>

を足す。

共有させたいObjectに同じtrasitionNameを指定

カード内のImageViewとプロフィール上部のImageViewのlayoutのxmlにtrasitionNameで同じ名前を指定します。

<ImageView
    android:id="@+id/profile_photo"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:transitionName="share_profile_photo_img"/>

これはプロフィール側の指定ですが、遷移元のカード側も同様に android:transitionName="share_profile_photo_img"を足します。
直接書くよりも、strings.xmlに引数切った方が共有しやすいと思います。

startActivityにActivityOptionsを足す

遷移タイミングのstartActivityのBundleにoptionsとしてActivityOptionsを足す。

public void startActivity (Intent intent, Bundle options)

↑に↓を足す。
https://developer.android.com/reference/android/app/ActivityOptions.html#makeSceneTransitionAnimation(android.app.Activity,%20android.util.Pair%3Candroid.view.View,%20java.lang.String%3E...)

実際のコードでは、

ActivityOptions.makeSceneTransitionAnimation(requireActivity(),android.util.Pair.create(view.photo, "share_profile_photo_img"))

をstartActivityの第二引数に渡しています。

遷移先のActivityでImageのローディングをする

↑のstartActivityのタイミングで表示するurlを渡しておきます。(実際の実装だと諸事情によりUrlのlistと選択しているurlを渡しています)
で、onCreateでsetContentView(view)後に、対象のImageViewにローディングをします。
transition_load.gif
このとき、ただロードするとロードよりも遷移が先にきてしまい、画像が用意されていないので背景の白色が一瞬うつってしまいます。
なので、ロード前に遷移を止めるActivity#postponeEnterTransition()を呼び出し、画像ロード後にActivity#startPostponedEnterTransition()を呼び出すと、白のチラツキなしに遷移ができるようになります。
https://developer.android.com/reference/android/app/Activity.html?hl=ja#postponeEnterTransition()
https://developer.android.com/reference/android/app/Activity.html?hl=ja#startPostponedEnterTransition()
多分よくある失敗がロードが失敗したタイミングで呼び出し忘れて永遠に遷移しない、だと思うのでわすれずに呼び出しましょう。

引っかかったポイント

画像がなめらかに移動せず、拡大してからちょうどいいサイズになるように見える

poi_transition_fail.gif
最初実装したときはこんな感じでした。一回画像が拡大してから移行しているように見え、スムーズじゃないですね。
原因としては、画像の拡大率。どちらのImageViewもandroid:scaleType="fitCenter"を設定していましたが、カード側が縦長、プロフィール側が横長でした。
なので、プロフィール側の画像サイズを必ず縦長にするようにして、回避しました。

プロフィールで画像を切り替えたときにカード側に伝える方法

これはActivityTransitionに直接関係ないのですが、Transitionで遷移→戻るのタイミングで、遷移を止めるActivity#postponeEnterTransition()のようなものが見当たりませんでした(あったら教えてほしい)
で、onActivityResultをつかってみたのですが、アニメーション遷移で遷移するタイミングで間に合わず、直前に表示されていた画像がチラついていました。
対応としては、EventBus的な機構を使って、カード側のFragmentをonCreate→onDestroyまでイベントを待機して、切り替えるたびに親画面に伝え、画像のIndexを切り替え、再表示タイミングでそのurlで画像を呼び出すとだいたいキャッシュされているのですぐに表示されるため、それでしのいでいます。
正直あんまりいいやり方ではないので、他にいいやり方があれば知りたいです。

簡単でしょ?

簡単じゃなかっ……
前述のデベロッパーブログに乗っているソースコードを読みつつ、適宜いろんなブログを見つつしてなんとかわかった感じです。
でも、これを入れるだけでなんかちょっと今どきのアプリ感は出るかなーと思うので、ぜひやってみてください!
poi_transition_success.gif

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?