How to fix jetpack navigation pop behaviour incorrect animation?

Viewed 2384

When using the jetpack navigation host component, I'm having an issue with the navigation "Pop Behaviour" using the a different animation than the one I'd like, and I'm not sure how to force a different one.

enter image description here When flowing between screens, I'm trying to get them to "flow from the right to the left" similar to iOS's navigation. However, when I add the pop behaviour so that Fragment 3 goes back directly to Fragment 1, going from Fragment 2 to Fragment 3 has Fragment 2 moving to the right, rather than to the left.

I've reproduced the issue in this repository: https://github.com/AtomicSimon/Android-Replication-Screen-Flow

Here's the simple screen flow I'm using:

Here's the navigation graph XML:


    <fragment
        android:id="@+id/fragment_1"
        android:label="fragment_fragment_1"
        android:name="com.example.android_replication_screen_flow.fragment_1"
        tools:layout="@layout/fragment_fragment_1">
        <action
            android:id="@+id/action_fragment_1_to_fragment_2"
            app:destination="@id/fragment_2"
            app:enterAnim="@anim/slide_in_from_the_right"
            app:exitAnim="@anim/slide_out_to_the_left"
            app:popEnterAnim="@anim/slide_in_from_the_left"
            app:popExitAnim="@anim/slide_out_to_the_right"/>
    </fragment>
    <fragment
        android:id="@+id/fragment_2"
        android:label="fragment_fragment_2"
        android:name="com.example.android_replication_screen_flow.fragment_2"
        tools:layout="@layout/fragment_fragment_2">
        <action
            android:id="@+id/action_fragment_2_to_fragment_3"
            app:destination="@id/fragment_3"
            app:enterAnim="@anim/slide_in_from_the_right"
            app:exitAnim="@anim/slide_out_to_the_left"
            app:popEnterAnim="@anim/slide_in_from_the_left"
            app:popExitAnim="@anim/slide_out_to_the_right"
            app:popUpTo="@+id/fragment_2"
            app:popUpToInclusive="true"/>
    </fragment>
    <fragment
        android:id="@+id/fragment_3"
        android:label="fragment_fragment_3"
        android:name="com.example.android_replication_screen_flow.fragment_3"
        tools:layout="@layout/fragment_fragment_3"/>

I'd like for Fragment 2 to leave the screen towards the left when going from Fragment 2 to Fragment 3 but I can't get it right.

3 Answers

In order to make this work you have to do the following:

i.) remove "popUpTo" from action "@+id/action_fragment_2_to_fragment_3"

ii.) add a new action to fragment_3 which navigates back to fragment_1 and clears the backstack for you

<fragment
    android:id="@+id/fragment_3"
    android:label="fragment_fragment_3"
    android:name="com.example.android_replication_screen_flow.fragment_3"
    tools:layout="@layout/fragment_fragment_3">

    <action
        android:id="@+id/backToFragment_1_action"
        app:destination="@id/fragment_1"
        app:enterAnim="@anim/enter_from_left"
        app:exitAnim="@anim/exit_to_right"
        app:popUpToInclusive="true"
        app:popUpTo="@id/fragment_1" />

</fragment>

iii.) in order to have the same behaviour when the user clicks the back button, you should add OnBackPressedCallback in onCreate() of Fragment_3 and call the "backToFragment_1_action".

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // This callback will only be called when MyFragment is at least Started.
    requireActivity().getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
        @Override
        public void handleOnBackPressed() {
            NavHostFragment.findNavController(Fragment_3.this).navigate(R.id. backToFragment_1_action);
        }
    });
}

I had the same problem.

What I did was

  • Don't use popUpTo
  • Make an action instead of just using the back stack, using popUpToInclusive.

Personally I think this is a bug in navigation with some animations.

I had the same issue and I think the issue is in how this is handled:

My navigation is: A <-> B -> C

So when going from A to B the backstack adds B, when going to C everything should be popped up. And exactly that is the problem.

A -> B should slide from right to left.

B -> A back (pop action) should slide the opposite way, from left to right.

But because of that I think the action in the XML applies to the view, not just one transition. So, whenever B will be popped, it goes to the right.

B -> C means, C slides in from the right, but B remembers that it must slide to the right to fulfil it's previously defined action.

Honestly knowing this it makes sense: A normal navigation to the front or back is animated as expected. When you pop everything from the stack is looks a bit like shuffling cards. You take one away and put in another.

It just doesn't work if you do it too often, because you have some crazy workflow (like I have, in more places than A-B-C), and it doesn't work, if you just want to use the back button and the navigation stack instead of defining back navigation actions separately every time.

Related