Общий элемент перехода Android между тремя фрагментами

Я пытаюсь реализовать несколько приятных переходов между фрагментами, используя общие элементы, и вот чего я хочу добиться:

введите здесь описание изображения

Когда я переключаюсь с фрагмента 1 на фрагмент 2:

  • фрагмент 1 исчезает
  • логотип перемещается в левый верхний угол
  • фрагмент 2 идет снизу.

Когда я переключаюсь с фрагмента 2 на фрагмент 3:

  • фрагмент 2 исчезает
  • логотип "не двигается"
  • Заголовок 1 перемещается влево
  • Название 2 идет справа
  • фрагмент 3 идет снизу

Вот настройки для фрагмента 1:

Fagment1.java:

fragment.setExitTransition("fade"); //parameter shortened for readability

XML:

<ImageView [...]
    android:id="@+id/octopuss"
    android:transitionName="@string/octopuss"/>

Вот настройки для фрагмента 2:

Фрагмент2.java:

fragment3.setEnterTransition("slide_bottom");
fragment3.setSharedElementEnterTransition("move");
fragment3.setExitTransition("fade");

XML:

<ImageView [...]
    android:transitionName="@string/octopuss"/>

<TextView [...]
    android:transitionName="title1"
    android:id="@+id/title1" />

Вызов фрагмента 2 в действии:

FragmentTransaction ft = getSupportFragmentManager().beginTransaction()
    .replace(R.id.fullscreen_content, fragment2)
    .addToBackStack("connection_transaction");
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)     
    ft.addSharedElement(findViewById(R.id.octopuss), getString(R.string.octopuss));
ft.commit();

Вот настройки для фрагмента 3:

Фрагмент3.java:

fragment3.setEnterTransition("slide_bottom");
fragment3.setSharedElementEnterTransition("slide_right");

XML:

<ImageView [...]
    android:transitionName="@string/octopuss"/>

<TextView [...]
    android:transitionName="title1"/>

Вызов фрагмента 3 в действии:

FragmentTransaction ft = getSupportFragmentManager().beginTransaction()
    .replace(R.id.fullscreen_content, fragment3)
    .addToBackStack("preferences_transaction");
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
    ft.addSharedElement(findViewById(R.id.title1), "title1");
ft.commit();

Каждый переход очень хорошо работает между фрагментом 1 и фрагментом 2.

Но когда я вызываю фрагмент 3, каждый фрагмент запускает свой enterTransition\exitTansition, как будто у них вообще не было общего элемента:

  • Заголовок 1 исчезает с фрагментом 2
  • Заголовок 2 идет снизу с фрагментом 3

Может ли кто-нибудь помочь мне найти причину? Что мне не хватает?


comment
Можете ли вы уточнить, какие общие элементы должны быть у фрагментов 2 и 3? Кажется, что фрагмент 2 содержит Заголовок 1, а фрагмент 3 содержит Заголовок 2, но это два отдельных элемента в переходе, который вы описываете. Есть ли у вас дополнительные элементы TextView, скрытые за кадром во фрагменте 2 или 3, чтобы можно было поделиться элементами?   -  person Lewis McGeary    schedule 12.01.2016
comment
Хорошая точка зрения ! Фактически, Title1 во фрагменте 2 и Title2 во фрагменте 3 должны быть общим элементом с trasitionName=title1 между этими фрагментами.   -  person Mino    schedule 13.01.2016


Ответы (1)


Это превратилось в довольно длинный ответ: объяснение, почему это не работает и как заставить его работать.

Проблема

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

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

Общий элемент — это не просто элемент, который перемещается независимо от остальной части макета во время перехода.

Итак, со всем сказанным; в этом примере первый переход, когда большой центральный логотип меняется на маленький логотип в углу, является отличным примером перехода общего элемента.

Второй на самом деле не является общим переходом элемента. Я не уверен, что содержит строка fragment3.setSharedElementEnterTransition("slide_right"); (я думаю, вы сократили ее для ясности), но я подозреваю, что она игнорируется, когда ваше приложение работает, поскольку это недопустимый переход общего элемента.

Нет смысла указывать общему элементу «скользить вправо», поскольку по определению направление, в котором будет двигаться элемент, зависит от того, где находится его аналог; он будет двигаться туда в любом направлении.

Фактический переход общего элемента между Заголовком 1 и Заголовком 2 вообще не будет выглядеть как нечто особенное, поскольку они имеют одинаковый размер в одном и том же месте, они просто останутся там.

Не все потеряно

Чтобы это работало с помощью перехода общего элемента, поместите заголовок 1 и заголовок 2 в оба фрагмента и добавьте два общих элемента. В одном фрагменте Заголовок 1 будет в нормальном положении, а Заголовок 2 будет скрыт с правой стороны экрана. В другом Заголовок 2 будет в обычном положении, а Заголовок 1 будет скрыт в левой части экрана.

Для ваших внеэкранных TextViews используйте android:translationX="-86dp" (или какой-либо другой номер, чтобы расположить его слева или справа от экрана).

Примечание: вы не увидите эффект атрибута translationX в предварительном просмотре макета, только когда запустите приложение.

Убедитесь, что вы сопоставили соответствующие имена переходов для title1 и title2.

person Lewis McGeary    schedule 13.01.2016
comment
Спасибо за это ! Вы правы, я вроде как плохо переделал принципы общих элементов. Конечно, код был сокращен для ясности, настоящее определение выглядит так: fragment.setExitTransition(TransitionInflater.from(context).inflateTransition(android.R.transition.move));. Более того, кажется, что только move действительно работает с общим элементом. Я попробую то, что вы предлагаете здесь, и дам вам принятый ответ на это полезное (не такое длинное) объяснение. - person Mino; 14.01.2016
comment
Я подтверждаю, что это работает, но возникает вопрос: как я могу получить «видимую» ширину «Title1», чтобы переместить «Title 2» с экрана независимо от размера экрана? Я пробовал: title2.setTranslationX(title2.getMeasuredWidth()); внутри onCreateView() безрезультатно.. - person Mino; 14.01.2016