it-roy-ru.com

Переход общего элемента не работает

Я сделал проект GitHub только с проблемой. Вы можете увидеть его/клонировать/построить здесь: https://git.io/vMPqb


Я пытаюсь заставить общие элементы работать для перехода фрагмента.

В проекте два FAB - Feather и Plane. Перо и плоскость являются общими элементами. При нажатии на «Перо» открывается SheetDialog, и «Перо» должно анимироваться в диалоговом окне «Плоскость». В данный момент этого не происходит, и я пытаюсь определить, почему.

Возможно, стоит отметить, что я запускаю это на API 24, поэтому проблемы с переходами, не поддерживаемыми ниже версии 21, не являются проблемой.

Может кто-нибудь сказать мне, почему не работают переходы общего элемента?

Чтобы повторить то, что есть в репо, есть четыре важных файла:

Основная деятельность

package test.example.fabpop;

import Android.os.Bundle;
import Android.support.design.widget.FloatingActionButton;
import Android.support.transition.ChangeBounds;
import Android.support.transition.Fade;
import Android.support.v4.app.FragmentTransaction;
import Android.support.v7.app.AppCompatActivity;
import Android.view.View;

public class MainActivity extends AppCompatActivity {

    FloatingActionButton fab_feather;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        fab_feather = (FloatingActionButton) findViewById(R.id.initial_fab_feather);
    }

    public void fabClick(View view) {
        SheetDialog dialogFragment = new SheetDialog();

        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        // This seemingly has no effect. I am trying to get it to work.
        transaction.addSharedElement(fab_feather, "transition_name_plane");

        dialogFragment.setSharedElementEnterTransition(new ChangeBounds());
        dialogFragment.setSharedElementReturnTransition(new Fade(Fade.OUT));

        dialogFragment.show(transaction, "frag_tag");
    }
}

activity_main.xml Layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:id="@+id/activity_main"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:paddingBottom="@dimen/activity_vertical_margin"
    Android:paddingLeft="@dimen/activity_horizontal_margin"
    Android:paddingRight="@dimen/activity_horizontal_margin"
    Android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="test.example.fabpop.MainActivity">

    <LinearLayout
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_alignParentEnd="true"
        Android:orientation="vertical">
        <TextView
            Android:layout_width="200dp"
            Android:layout_height="wrap_content"
            Android:text="Transition to a BottomSheetDialogFragment that shares this FAB"
            Android:textAlignment="center"/>

        <!--  Feather FAB  -->
        <Android.support.design.widget.FloatingActionButton
            Android:id="@+id/initial_fab_feather"
            Android:layout_width="52dp"
            Android:layout_height="52dp"
            Android:layout_margin="16dp"
            Android:layout_gravity="center"
            Android:onClick="fabClick"
            Android:transitionName="transition_name_feather"
            Android:src="@drawable/ic_feather"
            />
    </LinearLayout>


</RelativeLayout>

SheetDialog

package test.example.fabpop;

import Android.os.Bundle;
import Android.support.annotation.Nullable;
import Android.support.design.widget.BottomSheetDialogFragment;
import Android.view.LayoutInflater;
import Android.view.View;
import Android.view.ViewGroup;

public class SheetDialog extends BottomSheetDialogFragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater,
                             @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {

        return inflater.inflate(R.layout.dialog_sheet, container, false);
    }
}

dialog_sheet.xml Layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:orientation="vertical" Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <!--  Plane FAB  -->
    <Android.support.design.widget.FloatingActionButton
        Android:id="@+id/final_fab_plane"
        Android:layout_width="75dp"
        Android:layout_height="75dp"
        Android:layout_margin="16dp"
        Android:transitionName="transition_name_plane"
        Android:src="@drawable/ic_plane"
        />

</LinearLayout>

Разве невозможно иметь общий элемент при переходе между одним действием и одним фрагментом? Возможно, возможно только между Деятельностью к Деятельности или Фрагментом к Фрагменту, но не через два типа? Может быть, поэтому я не могу заставить его работать?

Обновление:

Я сейчас попытался добавить <item name="Android:windowContentTransitions">true</item> в тему приложения. 

Я также сейчас попытался при этом убедиться, что оба значения transitionName одинаковы для обоих представлений.

ни один из них не помог решить проблему.

17
atwrk

Прежде чем мы погрузимся в ...

Давайте сначала выделим некоторые моменты о том, как фреймворк Android выполняет магический переход с помощью общих элементов.

Совместное использование элемента перехода - это только одна из ложностей платформы Android. Когда вы выполняете переход с общим элементом, вы фактически не делитесь никакими представлениями между вашими действиями, например, каждое действие имеет независимое дерево представлений.

Предположим, что вы пытаетесь преобразовать element, идентифицированный element1, из Activity1 в element2 в Activity2

Фреймворк делает то, что ищет определенную информацию, такую ​​как размер (width, height) и положение (x, y) вашего element1 в Activity1. Затем он передает эту информацию в Activity2, применяет ее к element2 и запускает переход активности путем обратной анимации вашего element2, что создает иллюзию общего элемента.

Однако для этого необходимо создать Activity2, а view, соответствующую element2, нужно найти до запуска любой анимации.

В случае использования Fragment, вызов FragmentTransaction.commit() просто запланирует вашу транзакцию фрагмента (фрагмент не будет создан сразу), поэтому при создании вашего Activity2 ваш element2 отсутствует (как объяснено, потому что содержащий его фрагмент еще не был создан ).

Решение

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

Один из способов сделать это - изменить код так, чтобы он был похож на этот:

Деятельности2

class Activity2 extends Activity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ...
        // Tell the framework to wait.
        postponeEnterTransition();
    }
}

FRAGMENT2

class Fragment2 extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View element2 = getView().findViewById(R.id.element);
    sharedview.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
                // Tell the framework to start.
                sharedview.getViewTreeObserver().removeOnPreDrawListener(this);
                getActivity().startPostponedEnterTransition(); 
                return true;
         }
       });
       ...
    }
}

Дальнейшее чтение

Начало работы с переходами активности и фрагментов

8
Anix PasBesoin

Что вы ищете, так это пример: https://github.com/hujiaweibujidao/FabDialogMorph . Обратите внимание, что вы пытаетесь достичь не стандартного перехода Android, вам нужно создать свой собственный изменяющийся переход, основанный на переходе ChangeBounds. Первоначально, это было показано в Плед , благодаря Ник Батчер для этого, так что вы можете проверить его для получения дополнительных советов и фона.

1
rom4ek

Просто цитируя Android Docs

Начать действие с общим элементом

  1. Присвойте общее имя общим элементам в обоих макетах с помощью атрибута Android: transitionName.

Из того, что я вижу, оба ваших XML не имеют одинакового Android: transitionName.

Попробуйте изменить оба Android: transitionName в макете XML (activity_main.xml & dialog_sheet.xml) на одну и ту же строку, например: transition_plane_feather

Я сам не проверял коды, но думаю, что это может быть хорошей отправной точкой.

Бонусный совет

Если вы планируете полностью реализовать Material Design без совместимости с более низкими уровнями API (до Lollipop), я настоятельно рекомендую проверить образец, созданный дизайнером пользовательского интерфейса Google/UX: https://github.com/nickbutcher/ плед

Кроме того, посмотрите отличное дополнительное видео YouTube для этого образца: https://www.youtube.com/watch?v=EjTJIDKT72M

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

1
Nicholas Lie