Подтвердить что ты не робот

Как начать общий переход элементов с помощью фрагментов?

Я пытаюсь реализовать переходы между фрагментами, которые имеют "общие элементы", как описано в спецификациях нового материала. Единственный метод, который я могу найти в ActivityOptionsCompat.makeSceneTransitionAnimation, который я считаю, работает только на активность. Я искал эту же функциональность, но с фрагментами/для фрагментов.

4b9b3361

Ответ 1

У меня была такая же проблема, но она работала, добавляя новый фрагмент из другого фрагмента. Следующая ссылка очень полезна в этом: https://developer.android.com/training/material/animations.html#Transitions

Вот мой код, который работает. Я анимация ImageView от одного фрагмента к другому. Убедитесь, что View, который вы хотите оживить, имеет тот же самый android:transitionName в обоих фрагментах. Другое содержание не имеет большого значения.

В качестве теста вы можете скопировать это в оба ваших XML файла макета. Убедитесь, что изображение существует.

<ImageView
android:transitionName="MyTransition"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/test_image" />

Затем у меня есть 1 файл в моей папке res/transition с именем change_image_transform.xml.

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
    <changeImageTransform />
</transitionSet>

Теперь вы можете начать. Допустим, у вас есть фрагмент A, содержащий изображение, и вы хотите добавить фрагмент B.

Запустите это в фрагменте A:

@Override
public void onClick(View v) {
    switch(v.getId()) {
        case R.id.product_detail_image_click_area:
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
                setExitTransition(TransitionInflater.from(getActivity()).inflateTransition(android.R.transition.explode));

                // Create new fragment to add (Fragment B)
                Fragment fragment = new ImageFragment();
                fragment.setSharedElementEnterTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
                fragment.setEnterTransition(TransitionInflater.from(getActivity()).inflateTransition(android.R.transition.explode));

                // Our shared element (in Fragment A)
                mProductImage   = (ImageView) mLayout.findViewById(R.id.product_detail_image);

                // Add Fragment B
                FragmentTransaction ft = getFragmentManager().beginTransaction()
                        .replace(R.id.container, fragment)
                        .addToBackStack("transaction")
                        .addSharedElement(mProductImage, "MyTransition");
                ft.commit();
            }
            else {
                // Code to run on older devices
            }
            break;
    }
}

Ответ 2

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

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

Если вы сделаете свой адаптер просмотра списка для установки уникальных имен перехода в нужные вам виды (например, некоторый константный + определенный идентификатор элемента), а также измените фрагмент детали, чтобы установить те же самые имена перехода в целевые представления во время выполнения (onCreateView), переходы действительно работают!

Ответ 3

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

  • Не пытайтесь установить sharedElementsTransition в onCreateView вашего фрагмента. Вы должны определить их при создании экземпляра вашего фрагмента или в onCreate.

  • Обратите внимание на официальную документацию о возможных анимациях для переходов ввода/вывода и sharedElementTransition. Они не то же самое.

  • Судебная и ошибка:)

Ответ 4

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

Принятый ответ (от WindsurferOak и ar34z) работает, за исключением "незначительной" проблемы, которая вызвала исключение нулевого указателя при навигации с backStack. Кажется, что setSharedElementReturnTransition() должен быть вызван на целевой фрагмент вместо исходного фрагмента.

Итак, вместо:

setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));

он должен быть

fragment.setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));

https://github.com/tevjef/Rutgers-Course-Tracker/issues/8

Ответ 6

Ключ заключается в использовании пользовательской транзакции с

transaction.addSharedElement(sharedElement, "sharedImage");

Переход между двумя фрагментами между двумя фрагментами

В этом примере один из двух разных ImageViews должен быть переведен из ChooserFragment в DetailFragment.

В макете ChooserFragment нам нужны уникальные атрибуты transitionName:

<ImageView
    android:id="@+id/image_first"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_first"
    android:transitionName="fistImage" />

<ImageView
    android:id="@+id/image_second"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_second"
    android:transitionName="secondImage" />

В классе ChooserFragments нам нужно передать View, который был нажат, и идентификатор родительского Activity, который обрабатывает замену фрагментов (нам нужен идентификатор, чтобы узнать, какой ресурс изображения показывать в DetailFragment). Как подробно передавать информацию родительской активности, безусловно, рассматривается в другой документации.

view.findViewById(R.id.image_first).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if (mCallback != null) {
            mCallback.showDetailFragment(view, 1);
        }
    }
});

view.findViewById(R.id.image_second).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if (mCallback != null) {
            mCallback.showDetailFragment(view, 2);
        }
     }
});

В DetailFragment для элемента ImageView для общего элемента также нужен уникальный атрибут transitionName.

<ImageView
    android:id="@+id/image_shared"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:transitionName="sharedImage" />

В методе onCreateView() DetailFragment мы должны решить, какой ресурс изображения должен быть показан (если мы этого не сделаем, общий элемент исчезнет после перехода).

public static DetailFragment newInstance(Bundle args) {
    DetailFragment fragment = new DetailFragment();
    fragment.setArguments(args);
    return fragment;
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    super.onCreateView(inflater, container, savedInstanceState);
    View view = inflater.inflate(R.layout.fragment_detail, container, false);

    ImageView sharedImage = (ImageView) view.findViewById(R.id.image_shared);

    // Check which resource should be shown.
    int type = getArguments().getInt("type");

    // Show image based on the type.
    switch (type) {
        case 1:
            sharedImage.setBackgroundResource(R.drawable.ic_first);
            break;

        case 2:
            sharedImage.setBackgroundResource(R.drawable.ic_second);
            break;
    }

    return view;
}

Родительский Activity получает обратные вызовы и обрабатывает замену фрагментов.

@Override
public void showDetailFragment(View sharedElement, int type) {
    // Get the chooser fragment, which is shown in the moment.
    Fragment chooserFragment = getFragmentManager().findFragmentById(R.id.fragment_container);

    // Set up the DetailFragment and put the type as argument.
    Bundle args = new Bundle();
    args.putInt("type", type);
    Fragment fragment = DetailFragment.newInstance(args);

    // Set up the transaction.
    FragmentTransaction transaction = getFragmentManager().beginTransaction();

    // Define the shared element transition.
    fragment.setSharedElementEnterTransition(new DetailsTransition());
    fragment.setSharedElementReturnTransition(new DetailsTransition());

    // The rest of the views are just fading in/out.
    fragment.setEnterTransition(new Fade());
    chooserFragment.setExitTransition(new Fade());

    // Now use the image view and the target transitionName to define the shared element.
    transaction.addSharedElement(sharedElement, "sharedImage");

    // Replace the fragment.
    transaction.replace(R.id.fragment_container, fragment, fragment.getClass().getSimpleName());

    // Enable back navigation with shared element transitions.
    transaction.addToBackStack(fragment.getClass().getSimpleName());

    // Finally press play.
    transaction.commit();
}

Не забыть - сам Transition. Этот пример перемещает и масштабирует общий элемент.

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class DetailsTransition extends TransitionSet {

    public DetailsTransition() {
        setOrdering(ORDERING_TOGETHER);
        addTransition(new ChangeBounds()).
            addTransition(new ChangeTransform()).
            addTransition(new ChangeImageTransform());
    }

}

Ответ 7

Я искал SharedElement во фрагментах и нашел очень полезный исходный код на GitHub.

1. Сначала вы должны определить transitionName для своих объектов (например, ImageView) в макете обоих фрагментов (мы добавляем кнопку во фрагменте A для обработки события нажатия):

фрагмент A:

  <ImageView
    android:id="@+id/fragment_a_imageView"
    android:layout_width="128dp"
    android:layout_height="96dp"
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"
    android:layout_marginBottom="80dp"
    android:scaleType="centerCrop"
    android:src="@drawable/gorilla"
    android:transitionName="@string/simple_fragment_transition />

<Button
    android:id="@+id/fragment_a_btn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"
    android:layout_marginBottom="24dp"
    android:text="@string/gorilla" />

фрагмент B:

    <ImageView
    android:id="@+id/fragment_b_image"
    android:layout_width="match_parent"
    android:layout_height="250dp"
    android:scaleType="centerCrop"
    android:src="@drawable/gorilla"
    android:transitionName="@string/simple_fragment_transition" />
  1. Затем вы должны написать этот код в файле перехода в каталоге перехода (если у вас нет этого каталога, создайте его: res> new> Каталог ресурсов Android> Тип ресурса = переход> имя = change_image_transform):

change_image_transform.xml:

 <?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
  <changeBounds/>
  <changeTransform/>
  <changeClipBounds/>
  <changeImageTransform/>
</transitionSet>
  1. На последнем шаге вы должны заполнить коды в Java:

фрагмент A:

public class FragmentA extends Fragment {

    public static final String TAG = FragmentA.class.getSimpleName();


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_a, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        final ImageView imageView = (ImageView) view.findViewById(R.id.fragment_a_imageView);
        Button button = (Button) view.findViewById(R.id.fragment_a_btn);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                getFragmentManager()
                        .beginTransaction()
                        .addSharedElement(imageView, ViewCompat.getTransitionName(imageView))
                        .addToBackStack(TAG)
                        .replace(R.id.content, new FragmentB())
                        .commit();
            }
        });
    }
}

фрагмент B:

public class FragmentB extends Fragment {

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
            setSharedElementEnterTransition(TransitionInflater.from(getContext()).inflateTransition(android.R.transition.move));

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_b, container, false);
    }
}

не забудьте показать свой "А" фрагмент в своей деятельности:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getSupportFragmentManager()
                .beginTransaction()
                .add(R.id.content, new SimpleFragmentA())
                .commit();
    }

источник: https://github.com/mikescamell/shared-element-transitions