3

shared element transition replace the fragment, so I can't add it to the backstack and call popbackstack when the back arrow button is pressed. I have a main activity with inside a mainfragment, the main fragment handle a table layout so each tab is a fragment with inside a recycler view, when a recycler view element is clicked the shared element transition start to a new fragment that shows element details.

This is the adapter, where the element is clicked:

holder.image.setTransitionName("transition" + holder.getAdapterPosition());
if (fragment instanceof tab1_anime) {
     ((tab1_anime) fragment).openShowElementFragment(holder.getAdapterPosition(), v.findViewById(R.id.main_image));
}

This is the openShowElementFragment inside my tab fragment:

public void openShowElementFragment(int position, View view) {
        AddElement element = anime_list.get(position);
        ShowElementFragment showElementFragment = new ShowElementFragment();
        Bundle bundle = new Bundle();
        bundle.putString("transitionName", "transition" + position);
        bundle.putSerializable("element", element);
        bundle.putInt("position", position);
        bundle.putInt("from", 0);
        showElementFragment.setArguments(bundle);
        ((MainActivity) context).showFragmentWithTransition(this, showElementFragment, "showElementFragment", view, "transition" + position);
    }

this is the openshowelementfragment function called in the previous code block:

public void showFragmentWithTransition(Fragment current, Fragment newFragment, String tag, View sharedView, String sharedElementName) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        // check if the fragment is in back stack
        boolean fragmentPopped = fragmentManager.popBackStackImmediate(tag, 0);
        if (fragmentPopped) {

        } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                current.setSharedElementReturnTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
                current.setExitTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));

                newFragment.setSharedElementEnterTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
                newFragment.setEnterTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
            }
            fragmentManager.beginTransaction()
                    .replace(R.id.fragmentHolder, newFragment)
                    .addToBackStack(null)
                    .addSharedElement(sharedView, sharedElementName)
                    .commit();
        }
    }

and this is the backarrow button:

back_arrow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                getSupportFragmentManager().popBackStack();
            }
        });

If I try to add the new fragment instead of replace the old one, then there is not animations at all.

If I try to replace the old fragment with the new one and using anyway the addtobackstack(null) then the shared element transition works from start to end BUT the fragment at the end is without data, empty:

enter image description here

I tried also:

getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.fragmentHolder,  new MainFragment())
                .addToBackStack(null)
                .commit();

but in this way the shared element transition doesn't work on exit:

enter image description here

shybaka
  • 160
  • 1
  • 7

2 Answers2

0

Your so called sharedElementName is actually a transitionName.

a) The reference example doesn't directly manipulate the backstack:
Android Fragment Transitions: RecyclerView to ViewPager & Blog.

b) Manual transactions might require another order of method calls:

getSupportFragmentManager().beginTransaction()
    .addSharedElement(sharedElement, transitionName)
    .replace(R.id.container, newFragment)
    .addToBackStack(null)
    .commit();

Also see this example, how alternate transitions could be be set, compared to:

TransitionInflater.from(this).inflateTransition(R.transition.default_transition)

Whatever R.transition.default_transition may be.

It may look strange when using the same transition for both ways, instead of enter/exit transitions, alike NavAction would feature. FragmentNavigator.Extras could be used to apply enter/exit transitions, when using navigation component; this also can be combined with ActionBar. Option a) is probably less complicated. b) something alike this Kotlin example might make more sense. It's pointless to build clunky navigation FX when enter/exit transitions would be supported out-of-the-box. Maybe consider loading with Glide, when loading images.


Assume the following build.gradle; there's no need to reinvent the wheel.

dependencies {
    androidTestImplementation "androidx.navigation:navigation-testing:2.5.3"
    implementation 'androidx.navigation:navigation-runtime:2.5.3'
    implementation 'androidx.navigation:navigation-fragment:2.5.3'
    implementation 'androidx.navigation:navigation-ui:2.5.3'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.14.2' 
    implementation 'com.github.bumptech.glide:glide:4.14.2' 
}

Then Navigation with FragmentNavigator.Extras might rather be the current method:

Bundle navArgs = new Bundle();
navArgs.putInt("position", position);

FragmentNavigator.Extras extras = new FragmentNavigator.Extras.Builder()
    .addSharedElement(sharedElement, transitionName)
    .build();

Navigation.findNavController(view).navigate(
    R.id.details, // ID of Nav destination
    navArgs,      // Bundle of args
    null,         // NavOptions
    extras);

One can also define transitionName in XML <action/> nodes.

Martin Zeitler
  • 1
  • 19
  • 155
  • 216
0

I think your problem is related to exit transition as you get solution of empty list, now for exit transition effect check below code.

 public void showFragmentWithTransition(Fragment current, Fragment newFragment, String tag, View sharedView, String sharedElementName) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        // check if the fragment is in back stack
        boolean fragmentPopped = fragmentManager.popBackStackImmediate(tag, 0);
        if (fragmentPopped) {

        } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                current.setSharedElementReturnTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
                current.setExitTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));

                newFragment.setSharedElementEnterTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
                newFragment.setEnterTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
                newFragment.setExitTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
                newFragment.setSharedElementReturnTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
            }
             getSupportFragmentManager().beginTransaction()
                 .addSharedElement(sharedElement, transitionName)
                 .replace(R.id.container, newFragment)
                 .addToBackStack(null)
                 .commit();
        }
    }

Here I add two new lines for exit transitions.

            newFragment.setExitTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
            newFragment.setSharedElementReturnTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));

If its not work then follow below link, I think it will help you. https://medium.com/@bherbst/fragment-transitions-with-shared-elements-7c7d71d31cbb

Heet Changela
  • 565
  • 1
  • 11
  • Using the same transition twice doesn't make sense... it's usually two transitions, while one can assign four different ones. – Martin Zeitler Jan 16 '23 at 12:34