読者です 読者をやめる 読者になる 読者になる

fresh digitable

セミコロンたちが躍動する おいらのコードを 皆さんに 見せたいね

RecyclerViewの中の要素をshared elementsにしてアニメーションする

今作っているツイッタークライアントは、タイムラインのユーザアイコンがタップされたらユーザ情報Activityに遷移するのだが、そのときにタップされたユーザアイコンが移動してユーザ情報Activityのユーザアイコンに重なるアニメーションを実装した。現時点ではAndroid 5.0 (API level 21)以上で有効。

参考:developer.android.com

まずは遷移元(タイムライン)と先(ユーザ情報)のActivityにWindow.requestFeature()する。

// setContentView()の前に行う
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
}

遷移元と先のビューにユニークなtransitionNameをつける。RecyclerViewの中の要素にtransitionNameをつけるときはアニメーションさせようとする直前にセットしておかないとユニークにならないようで、カスタムビューの中でinflateした後にセットするとうまくいかなかった(タイムライン→ユーザ情報はうまくいくが、そこからbackボタンで戻るときにアニメーションの起点が右下とか左下になったりした)。クリックされたビューがアニメーションするので、クリックリスナの中でやってしまっている。

userIcon.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View view) {
    ViewCompat.setTransitionName(view, "user_icon");
  }
});

ActivityOptionを渡してstartActivity()する。同様に上のコードのクリックリスナの中でやっている。

Intent intent = new Intent(context, UserInfoActivity.class);
ActivityCompat.startActivity(this, intent,
    ActivityOptionsCompat.makeSceneTransitionAnimation(this, userIcon, "user_icon").toBundle());

UserInfoActivity.start(Activity, View)みたいなユーティリティメソッドの中でやってしまうのもありかもしれない。

public static Intent createIntent(Context context) {
  return new Intent(context, UserInfoActivity.class);
}

public static void start(Activity activity, View userIcon) {
  final Intent intent = createIntent(activity.getApplicationContext());
  ViewCompat.setTransitionName(userIcon, "user_icon");
  ActivityCompat.startActivity(activity, intent,
      ActivityOptionsCompat.makeSceneTransitionAnimation(activity, userIcon, "user_icon").toBundle());
}