Change z-order of Fragments during ongoing FragmentTransaction

android, android-animation, android-fragments, fragmenttransaction

Solution

I also had this problem and the only workaround I have been able to find is to place another FrameLayout directly under the one that holds the current fragment. Then I transition my new fragment into the alternate FrameLayout (which has a higher z-ordering than the FrameLayout below it) and remove the old fragment from the original FrameLayout in the same transaction. Something like this:

<FrameLayout
    android:id="@+id/video_list_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</FrameLayout>

<FrameLayout
    android:id="@+id/video_player_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</FrameLayout>

Yes, I know this adds an additional view to the hierarchy but it doesn't increase the tree depth. For additional performance boost I override onCreateAnimator in my fragments to offload the animation to the hardware layer, like so:

@Override
public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
    Animator animation = super.onCreateAnimator(transit, enter, nextAnim);

    // HW layer support only exists on API 11+
    if (Build.VERSION.SDK_INT >= 11) {
        if (animation == null && nextAnim != 0) {
            animation = AnimatorInflater.loadAnimator(getActivity(), nextAnim);
        }

        if (animation != null) {
            animation.addListener(new LayerEnablingAnimatorListener(getView()));
        }
    }

    return animation;
}

And this is LayerEnablingAnimatorListener:

public class LayerEnablingAnimatorListener extends AnimatorListenerAdapter {

    private final View mTargetView;
    private int mLayerType;

    public LayerEnablingAnimatorListener(View targetView) {
        mTargetView = Objects.requireNonNull(targetView, "Target view cannot be null");
    }

    public View getTargetView() {
        return mTargetView;
    }

    @Override
    public void onAnimationStart(Animator animation) {
        super.onAnimationStart(animation);
        mLayerType = mTargetView.getLayerType();
        mTargetView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
    }

    @Override
    public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation);
        mTargetView.setLayerType(mLayerType, null);
    }
}

Problem

Is there a way how to change the z-order in which are fragments displayed during an ongoing FragmentTransaction? I've an animation where both fragments overlaps each other and I would like to have the fragment which slides from the right (the second fragment) displayed under the other one which slides to the left. Right now they are displayed in opposite order during the transaction. Here is code of one of my animations: ``` <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="400" android:zAdjustment="bottom"> <scale android:toXScale="1" android:fromXScale="0.9" android:pivotX="50%p" android:pivotY="50%p" android:toYScale="1" android:startOffset="300" android:fromYScale="0.9"/> <translate android:fromXDelta="50%p" android:interpolator="@android:interpolator/overshoot" android:toXDelta="0"/> </set> ``` And here is the code of the transaction ``` FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.show(fragmentToShow).hide(fragmentToHide).commit(); ``` I would like to have the `fragmentToHide` to appear under the `fragmentToShow`. I've tried to tackle with the `android:zAdjustment` property, but since it apparently works only for window animations it just haven't worked for me.

Original source