Habeeb Rahman
Habeeb Rahman

Reputation: 405

Animation for BottomNavigation Fragments with Architecture Navigation Components

I have successfully integrated the bottom navigation with the latest android architecture navigation components. The following is my complete code.

  1. Navigation
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/mobile_navigation"
    app:startDestination="@+id/navigation_home">

    <fragment
        android:id="@+id/navigation_home"
        android:name="in.zedone.bottomsample.ui.home.HomeFragment"
        android:label="@string/title_home"
        tools:layout="@layout/fragment_home" />

    <fragment
        android:id="@+id/navigation_saloons"
        android:name="in.zedone.bottomsample.ui.saloons.SaloonsFragment"
        android:label="@string/title_saloon"
        tools:layout="@layout/fragment_saloons" />

    <fragment
        android:id="@+id/navigation_offers"
        android:name="in.zedone.bottomsample.ui.offers.OffersFragment"
        android:label="@string/title_offer"
        tools:layout="@layout/fragment_offers" />

    <fragment
        android:id="@+id/navigation_account"
        android:name="in.zedone.bottomsample.ui.account.AccountFragment"
        android:label="@string/title_account"
        tools:layout="@layout/fragment_account" />

</navigation>
  1. BottomNavigationView
<com.google.android.material.bottomnavigation.BottomNavigationView
     android:id="@+id/nav_view"
     android:layout_width="0dp"
     android:layout_height="wrap_content"
     android:layout_marginStart="0dp"
     android:layout_marginEnd="0dp"
     android:background="?android:attr/windowBackground"
     app:labelVisibilityMode="labeled"
     app:itemTextAppearanceActive="@style/BottomNavigationView.Active"
     app:itemTextAppearanceInactive="@style/BottomNavigationView"
     app:layout_constraintBottom_toBottomOf="parent"
     app:layout_constraintLeft_toLeftOf="parent"
     app:layout_constraintRight_toRightOf="parent"
     app:menu="@menu/bottom_nav_menu" />
  1. MainActivity
BottomNavigationView navView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
                R.id.navigation_home, R.id.navigation_saloons, R.id.navigation_offers,R.id.navigation_account)
                .build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(navView, navController);

Now how can I add transition/animation on select each tab/fragment in bottom navigation?

Upvotes: 14

Views: 12557

Answers (3)

J.Grbo
J.Grbo

Reputation: 475

You can also do it with keeping setupWithNavController by overriding onCreateAnimation() in each Fragment and checking whether or not you're entering or exiting the Fragment with the enter parameter and then creating the appropriate Animation with AnimationUtils.loadAnimation(context, animationId).

override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
    return if (enter) {
        AnimationUtils.loadAnimation(context, R.anim.fade_in)
    } else {
        AnimationUtils.loadAnimation(context, R.anim.fade_out)
    }
}

EDIT as a response to iloo:

According to Material Design (https://material.io/components/bottom-navigation#behavior) you shouldn't be doing that in the first place, but I guess it's still achievable.

Since when using setupWithNavController all destinations are top level there will ever be only one previousBackStackEntry whose destination points to the home destination, therefore previousBackStackEntry is not much of a help in figuring out which Fragment are you coming from.

Other approach could be to have a public variable in the Activity, where you will store the last destination you were in and set that variable in each Fragment upon resuming. And you can check that variable in onAnimationCreate to know which Fragment you're coming from and apply an appropriate animation.

Upvotes: 1

thegirlincode
thegirlincode

Reputation: 404

Instead of using setupWithNavController function, follow this way.

First, create your NavOptions which include animation shown below.

val options = NavOptions.Builder()
            .setLaunchSingleTop(true)
            .setEnterAnim(R.anim.enter_from_bottom)
            .setExitAnim(R.anim.exit_to_top)
            .setPopEnterAnim(R.anim.enter_from_top)
            .setPopExitAnim(R.anim.exit_to_bottom)
            .setPopUpTo(navController.graph.startDestination, false)
            .build()

Then use setOnNavigationItemSelectedListener to navigate with animation like that.

bottomNavigationView.setOnNavigationItemSelectedListener { item ->
        when(item.itemId) {
            R.id.fragmentFirst -> {
                navController.navigate(R.id.fragmentFirst,null,options)
            }
            R.id.fragmentSecond -> {
                navController.navigate(R.id.fragmentSecond,null,options)
            }
            R.id.fragmentThird -> {
                navController.navigate(R.id.fragmentThird,null,options)
            }
        }
         true
    }

Finally, you should prevent same item selection case so you can add below code.

bottomNavigationView.setOnNavigationItemReselectedListener { item ->
        return@setOnNavigationItemReselectedListener

I used bottomNavigation like that in my project to add animation for page transitions. I hope it helped.

Upvotes: 17

Nimesh Hirpara
Nimesh Hirpara

Reputation: 41

its work with BottomNavigationView's siblings fragment also(JetPack Navigation Components)

// FragmentA.kt
override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)

  exitTransition = MaterialFadeThrough()
}


// FragmentB.kt
override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)

  enterTransition = MaterialFadeThrough()
}

Upvotes: 4

Related Questions