11

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.

simekadam
  • 7,334
  • 11
  • 56
  • 79
  • 1
    I am facing a similar problem. Have you found a way to change the z-order so that the appearing fragment is on top during the .replace() transition? – Moritz May 25 '14 at 09:05

2 Answers2

3

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);
    }
}
John Busby
  • 31
  • 2
  • layering in two different frames worked for me, but pretty ugly solution, though at the moment the best I know for fragments – arberg Apr 10 '19 at 15:45
3

Use ViewCompat.setTranslationZ(), and the following in your net fragment

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    ViewCompat.setTranslationZ(getView(), 1f);
}

The default trasnlationZ is 0.

Cody
  • 4,353
  • 4
  • 39
  • 42