Background
I have an activity with a fragment that needs to be animated when being created, but not when the orientation changes .
The fragment is being inserted into a layout dynamically, as it's a part of a navigation-drawer-style activity.
The 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 each time I rotate the device.
What I've done
I've added this to the fragment:
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
and this to the 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've tried
- I've tried to fix it by using "replace" instead of "add". It didn't help.
- I've also tried to always perform the replacement of the fragment, and if the fragment is already there, do it without animation (on the same fragment).
- if I remove the setRetainInstance call, it works, but I want to avoid re-creating the fragment.
Question
- How can I solve this issue?
- Why do I still get an animation for the adding of the fragment?
- What happens when other configurations change?
Workaround #1
This solution works in general, but it causes bad things to the lifecycle you've 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 want to see what can be done, because this can cause things you didn't want to occur(onDetach for the fragment, for example).
Workaround #2
One way to solve this is to avoid adding the animation via the fragmentManager, and just do it for the view itself within the fragment lifecycle. This is how 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));
}