Как начать общий переход элемента с помощью фрагментов?
Я пытаюсь реализовать переходы между фрагментами, которые имеют "общие элементы", как описано в новых спецификациях material design.
Единственный метод, который я могу найти -ActivityOptionsCompat.makeSceneTransitionAnimation, который, я считаю, работает только на деятельности.
Я искал эту же функциональность, но с/для фрагментов.
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), переходы на самом деле работают!
общие элементы работают с фрагментами, но есть некоторые вещи, чтобы иметь в виду:
не пытайтесь установить
sharedElementsTransitionнаonCreateViewваш фрагмент. Вы должны определить их при создании экземпляра фрагмента илиonCreate.обратите внимание на официальную документацию о возможных анимациях для переходов входа/выхода и sharedElementTransition. Это не одно и то же.
проб и ошибок :)
Это должен быть комментарий к принятому ответу, так как я не могу его прокомментировать.
принятый ответ (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));
ключ должен использовать пользовательскую транзакцию с
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