How to start the general transition of elements using fragments?

I am trying to implement transitions between fragments that have “common elements”, as described in the specifications of the new material. The only method I can find in ActivityOptionsCompat.makeSceneTransitionAnimation , which I believe works only for activity. I was looking for the same functionality, but with fragments / for fragments.

+57
android material-design fragment
Oct 25 '14 at 10:50
source share
7 answers

I had the same problem, but it worked by adding a new fragment from another fragment. The following link is very useful in this: https://developer.android.com/training/material/animations.html#Transitions

Here is my code that works. I am an ImageView animation from one fragment to another. Make sure the View you want to animate has the same android:transitionName in both snippets. Other content doesn't really matter.

As a test, you can copy this into both of your XML layout files. Make sure the image exists.

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

Then I have 1 file in my res/transition folder called change_image_transform.xml .

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

Now you can start. Suppose you have fragment A containing an image and you want to add fragment B.

Run this in fragment 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; } } 
+45
Nov 27 '14 at 15:17
source share

I am posting this as an answer since I am new here and cannot comment.

Transitions of fragments of shared elements work with ListViews if the source and target views have the same (and unique) transition name.

If you make your list view adapter to set unique transition names to the views you need (for example, some constant + a specific element identifier), and also change the part fragment to set the same transition names to the destination views at runtime (onCreateView), transitions really work!

+21
Nov 02 '14 at 21:11
source share

Common elements work with fragments, but there are some things to keep in mind:

  • Do not try to set sharedElementsTransition to onCreateView your fragment. You must define them when instantiating your fragment or in onCreate .

  • Check out the official documentation on possible animations for I / O transitions and sharedElementTransition. They are not the same.

  • Judicial and error :)

+11
Apr 21 '15 at 16:11
source share

This should be a comment on the accepted answer, as I cannot comment on it.

The accepted answer (from WindsurferOak and ar34z) works, except for a "minor" problem that caused a null pointer exception when navigating from backStack. It seems that setSharedElementReturnTransition() should be called on the target fragment instead of the original fragment.

So, instead of:

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

he should be

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

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

+3
May 04 '16 at 6:37 a.m.
source share

The key is to use a custom transaction with

 transaction.addSharedElement(sharedElement, "sharedImage"); 



Transition between two fragments between two fragments

In this example, one of two different ImageViews should be translated from ChooserFragment to DetailFragment .

In the ChooserFragment layout ChooserFragment we need the unique transitionName attributes:

 <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" /> 

In the ChooserFragments class ChooserFragments we need to pass the View that was clicked and the identifier of the parent Activity that handles the replacement of the fragments (we need an identifier to find out which image resource to show in DetailFragment ). How to convey in detail the information of parental activity, of course, is discussed in other documentation.

 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); } } }); 

In the DetailFragment for an ImageView element for a shared element, a unique transitionName attribute is also needed.

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

In the onCreateView() DetailFragment we must decide which image resource should be shown (if we do not, the common element will disappear after the transition).

 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; } 

Parent Activity receives callbacks and handles fragment replacement.

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

Do not forget - Transition itself. This example moves and scales a common item.

 @TargetApi(Build.VERSION_CODES.LOLLIPOP) public class DetailsTransition extends TransitionSet { public DetailsTransition() { setOrdering(ORDERING_TOGETHER); addTransition(new ChangeBounds()). addTransition(new ChangeTransform()). addTransition(new ChangeImageTransform()); } } 
0
Aug 03 '17 at 9:31 on
source share

I searched for SharedElement in snippets and found very useful source code on GitHub.

1. First you must define a transitionName for your objects (for example, ImageView) in the layout of both fragments (we add a button in fragment A to handle the click event):

fragment 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" /> 

fragment 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. Then you should write this code in the transition file in the transition directory (if you do not have this directory, create it: res> new> Android resource directory> Resource type = transition> name = 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. In the last step, you should fill in the codes in Java:

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

fragment 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); } } 

do not forget to show your "A" fragment in your activity:

  @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getSupportFragmentManager() .beginTransaction() .add(R.id.content, new SimpleFragmentA()) .commit(); } 

source: https://github.com/mikescamell/shared-element-transitions

0
Jul 29 '19 at 4:58
source share



All Articles