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



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

624   6  

6 ответов:

у меня была та же проблема, но она работала, добавляя новый фрагмент из другого фрагмента. Следующая ссылка очень полезна для начала работы над этим: 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;
    }
}

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

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

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

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

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

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

  3. проб и ошибок :)

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

принятый ответ (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

ключ должен использовать пользовательскую транзакцию с

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 из общего элемента также требуется уникальный .

<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's 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());
    }

}

Comments

    Ничего не найдено.