Background
I have activity with a fragment that needs to be animated when creating, but not when changing orientation.
The fragment is inserted dynamically into the layout, as it is part of the activity of the navigation box style.
Problem
I wanted to avoid re-creating the fragment for configuration changes, so I used setRetainInstance in the fragment. It works, but for some reason, the animation also restarts every time the device is rotated.
What I've done
I added this to the snippet:
@Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); }
and this is for activity:
final FragmentManager fragmentManager = getSupportFragmentManager(); final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); MyFragment fragment= (MyFragment) fragmentManager.findFragmentByTag(MyFragment.TAG); if (fragment== null) { fragmentTransaction.setCustomAnimations(R.anim.slide_in_from_left, R.anim.slide_out_to_right); fragment= new MyFragment(); fragmentTransaction .add(R.id.fragmentContainer, fragment, MyFragment.TAG).commit(); }
fragment_container.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/fragmentContainer" android:layout_width="match_parent" android:layout_height="match_parent" />
What i tried
- I tried to fix this by using instead of "add" instead of "replace" instead of "replace". It did not help.
- I also tried to always replace a fragment, and if the fragment already exists, do it without animation (on the same fragment).
- If I delete the setRetainInstance call, it works, but I want to avoid re-creating the fragment.
Question
- How can I solve this problem?
- Why am I still getting animation to add a fragment?
- What happens when other configurations change?
Workaround โ1
This solution works in general, but it harms the life cycle that you tried to achieve:
MyFragment fragment= (MyFragment) fragmentManager.findFragmentByTag(MyFragment.TAG); if (MyFragment== null) { MyFragment= new MyFragment(); fragmentManager.beginTransaction().setCustomAnimations(R.anim.slide_in_from_left, R.anim.slide_out_to_right) .replace(R.id.fragmentContainer, fragment, MyFragment.TAG).commit(); } else { //workaround: fragment already exists, so avoid re-animating it by quickly removing and re-adding it: fragmentManager.beginTransaction().remove(fragment).commit(); final Fragment finalFragment = fragment; new Handler().post(new Runnable() { @Override public void run() { fragmentManager.beginTransaction().replace(R.id.fragmentContainer, fragment, finalFragment .TAG).commit(); } }); }
I would still like to see what can be done, because it can lead to the fact that you do not want to meet (for example, onDetach for a fragment).
Workaround number 2
One way to solve this problem is to not add animation through the fragmenter and just do it for the view itself inside the fragment life cycle. Here's what it looks like:
Basefragment
@Override public void onViewCreated(final View rootView, final Bundle savedInstanceState) { super.onViewCreated(rootView, savedInstanceState); if (savedInstanceState == null) rootView.startAnimation(AnimationUtils.loadAnimation(getActivity(), R.anim.slide_in_from_left)); } @Override public void onDestroyView() { super.onDestroyView(); if (!getActivity().isChangingConfigurations()) getView().startAnimation(AnimationUtils.loadAnimation(getActivity(), R.anim.fade_out)); }