Переход общего элемента: активность во фрагмент, вложенный в другую активность

Я пытаюсь добавить общий переход элемента в мое приложение.

Сценарий заключается в том, что пользователь нажимает на миниатюру изображения, чем открывает другое действие с полным просмотром изображения на экране.

Это работает отлично, если общий вид размещается непосредственно в макете целевой активности. Работает сглаженно для анимации ввода/выхода. Но когда я пытаюсь добиться аналогичного эффекта в фрагменте, который вложен в целевой активности, этот подход не работает. Смешно, что анимация ввода не отображается, но анимация выхода работает нормально.

Другая еще более сложная иерархия представлений заключается в том, что если целевое представление (ImageView) размещено в представлении пейджера, который размещается в макете кадра целевой активности.

У кого-то была такая же проблема?

Изменить: Мой код прослушивания кликов

public class OnClickPicture extends OnClickBase {
  private ObjectPicture object;

  public OnClickPicture(Activity_Parent activity, ObjectPicture object) {
    super(activity);
    this.object = object;
  }

  public void onClick(View v) {

    picasso.load(object.getFullUrl()).fetch();
    Intent intent = new Intent(activity, ActivityPicture.class);
    intent.putExtra("picture_object", helper.gson.toJson(object));

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && v != null) {
      Pair<View, String> p1 = Pair.create(v, "image");
      ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, p1);
      activity.startActivity(intent, options.toBundle());
    } else {
      activity.startActivity(intent);
    }

  }

}

Ответы

Ответ 1

Способ работы переходов требует создания, измерения и компоновки нового действия до того, как произойдут какие-либо анимации. Это позволяет найти представление, которое вы хотите оживить, и создать соответствующую анимацию.

В вашем случае это не происходит, потому что, как указано в документах, все FragmentTransaction.commit() - это работа по расписанию. Это происходит не сразу. Поэтому, когда среда создает свою активность, она не может найти представление, которое вы хотите оживить. Вот почему вы не видите анимацию записи, но видите анимацию выхода. Вид есть, когда вы покидаете активность.

Решение достаточно просто. Прежде всего, вы можете попробовать FragmentManager.executePendingTransactions(). Этого может быть недостаточно. Рамка переходов имеет другое решение:

В onCreate of Activity postponeEnterTransition(). Это говорит платформе ждать, пока вы скажете, что ее безопасно создать анимацию. Это означает, что вам нужно сказать, что это безопасно (через вызов startPostponedEnterTransition()) в какой-то момент. В вашем случае это, вероятно, будет в Fragments onCreateView.

Вот пример того, как это может выглядеть:

Активность B

@Override
protected void onCreate(Bundle savedInstanceState) {
    // etc
    postponeEnterTransition();
}

Фрагмент B

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View sharedView = root.findViewById(R.id.shared_view);
    sharedview.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            sharedview.getViewTreeObserver().removeOnPreDrawListener(this);
            getActivity().startPostponedEnterTransition();
            return true;
        }
    });
}

Благодаря Алексу Локвуду за его подробные сообщения в блоге о структуре переходов.