Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding custom transition animations to bottom navigation setup with jetpack navigation

I am working on an app using jetpack components. I stitched up the bottom navigation with three fragments as described in the guide. However, I can't figure out how to change the transition animation when switching between the fragments on pressing the corresponding navigation button.

As far as I know, there are two ways of creating transitions:

  • Passing them as options in navigate(), which isn't being explicitly called in this case;
  • Using an action with animation attributes, but don't know how to tell the navigation to use these actions. Maybe giving it a specific id would work?

So how do I set a custom transition animation without having to give up using BottomNavigation.setupWithNavController(navController)

like image 347
aksh1618 Avatar asked Jan 24 '19 10:01

aksh1618


2 Answers

I think you can't, but would be interested into a solution.

Here is a workaround, if it helps:

Don't tie the bottom nav with the nav controller (don't do what's indicated in the guide). Manage the transition yourself by setting the handler like so:

    bottomNav!!.setOnNavigationItemSelectedListener { item ->
        selectFragment(item)
        false
    }

Then create transitions between each fragment and manage them yourself in the handler. Here is an example with 3:

private fun selectFragment(item: MenuItem) {
    if (selectedItem == -1)
        navController.navigate(item.itemId)
    else
        navController.navigate(
                when (item.itemId) {
                    R.id.interviewsFragment ->
                        if (selectedItem == R.id.personsFragment)
                            R.id.action_personsFragment_to_interviewsFragment
                        else
                            R.id.action_questionListsFragment_to_interviewsFragment
                    R.id.personsFragment ->
                        if (selectedItem == R.id.interviewsFragment)
                            R.id.action_interviewsFragment_to_personsFragment
                        else
                            R.id.action_questionListsFragment_to_personsFragment
                    R.id.questionListsFragment ->
                        if (selectedItem == R.id.interviewsFragment)
                            R.id.action_interviewsFragment_to_questionListsFragment
                        else
                            R.id.action_personsFragment_to_questionListsFragment
                    else -> item.itemId
                })

    selectedItem = item.itemId


    // uncheck the other items.
    for (i in 0 until bottomNav!!.menu.size()) {
        val menuItem = bottomNav!!.menu.getItem(i)
        if (menuItem.itemId == item.itemId) menuItem.isChecked = true
    }
}

Define the animations in the navigation map. Here is an example with the 3 fragments and the animation moves toward the item being the selected one so that it feels natural:

<fragment
    android:id="@+id/interviewsFragment"
    android:name="com.unludo.interview.interview.list.InterviewsFragment"
    android:label="InterviewsFragment" >
    <action
        android:id="@+id/action_interviewsFragment_to_personsFragment"
        app:destination="@id/personsFragment"
        app:enterAnim="@anim/enter_from_right"
        app:exitAnim="@anim/exit_to_left" />
    <action
        android:id="@+id/action_interviewsFragment_to_questionListsFragment"
        app:destination="@id/questionListsFragment"
        app:enterAnim="@anim/enter_from_right"
        app:exitAnim="@anim/exit_to_left" />
</fragment>
<fragment
    android:id="@+id/personsFragment"
    android:name="com.unludo.interview.persons.list.PersonsFragment"
    android:label="PersonsFragment" >
    <action
        android:id="@+id/action_personsFragment_to_interviewsFragment"
        app:destination="@id/interviewsFragment"
        app:enterAnim="@anim/enter_from_left"
        app:exitAnim="@anim/exit_to_right" />
    <action
        android:id="@+id/action_personsFragment_to_questionListsFragment"
        app:destination="@id/questionListsFragment"
        app:enterAnim="@anim/enter_from_right"
        app:exitAnim="@anim/exit_to_left" />
</fragment>
<fragment
    android:id="@+id/questionListsFragment"
    android:name="com.unludo.interview.questions.lists.QuestionListsFragment"
    android:label="QuestionListsFragment" >
    <action
        android:id="@+id/action_questionListsFragment_to_personsFragment"
        app:destination="@id/personsFragment"
        app:enterAnim="@anim/enter_from_left"
        app:exitAnim="@anim/exit_to_right" />
    <action
        android:id="@+id/action_questionListsFragment_to_interviewsFragment"
        app:destination="@id/interviewsFragment"
        app:enterAnim="@anim/enter_from_left"
        app:exitAnim="@anim/exit_to_right" />
</fragment>

I think this behaviour could be managed by the component itself but for now, I think we have to manage by hands.

Cheers :)

like image 144
unludo Avatar answered Oct 25 '22 07:10

unludo


I believe you can achieve this behavior by creating versions of the R.anim.nav_default_[Enter/Exit/PopEnter/PopExit] animation files and placing them in your anim resource directory. The component will use these files for the default animations then. It feels like it shouldn't work like that but at the moment it does.

like image 2
Garry McKee Avatar answered Oct 25 '22 07:10

Garry McKee