Nested fragments disappear during transition animation

So there seem to be a lot of different workarounds for this, but based on @Jayd16’s answer, I think I’ve found a pretty solid catch-all solution that still allows for custom transition animations on child fragments, and doesn’t require doing a bitmap cache of the layout.

Have a BaseFragment class that extends Fragment, and make all of your fragments extend that class (not just child fragments).

In that BaseFragment class, add the following:

// Arbitrary value; set it to some reasonable default
private static final int DEFAULT_CHILD_ANIMATION_DURATION = 250;

@Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
    final Fragment parent = getParentFragment();

    // Apply the workaround only if this is a child fragment, and the parent
    // is being removed.
    if (!enter && parent != null && parent.isRemoving()) {
        // This is a workaround for the bug where child fragments disappear when
        // the parent is removed (as all children are first removed from the parent)
        // See https://code.google.com/p/android/issues/detail?id=55228
        Animation doNothingAnim = new AlphaAnimation(1, 1);
        doNothingAnim.setDuration(getNextAnimationDuration(parent, DEFAULT_CHILD_ANIMATION_DURATION));
        return doNothingAnim;
    } else {
        return super.onCreateAnimation(transit, enter, nextAnim);
    }
}

private static long getNextAnimationDuration(Fragment fragment, long defValue) {
    try {
        // Attempt to get the resource ID of the next animation that
        // will be applied to the given fragment.
        Field nextAnimField = Fragment.class.getDeclaredField("mNextAnim");
        nextAnimField.setAccessible(true);
        int nextAnimResource = nextAnimField.getInt(fragment);
        Animation nextAnim = AnimationUtils.loadAnimation(fragment.getActivity(), nextAnimResource);

        // ...and if it can be loaded, return that animation's duration
        return (nextAnim == null) ? defValue : nextAnim.getDuration();
    } catch (NoSuchFieldException|IllegalAccessException|Resources.NotFoundException ex) {
        Log.w(TAG, "Unable to load next animation from parent.", ex);
        return defValue;
    }
}

It does, unfortunately, require reflection; however, since this workaround is for the support library, you don’t run the risk of the underlying implementation changing unless you update your support library. If you’re building the support library from source, you could add an accessor for the next animation resource ID to Fragment.java and remove the need for reflection.

This solution removes the need to “guess” the parent’s animation duration (so that the “do nothing” animation will have the same duration as the parent’s exit animation), and allows you to still do custom animations on child fragments (e.g. if you’re swapping child fragments around with different animations).

Leave a Comment