Activity-Based Bottom Navigation Using Shared Element Transition with BottomNavigationView

Kelvin Watson
5 min readAug 30, 2023

Using BottomNavigationView with fragments is well documented. The Jetpack Navigation Component supports fragment-based navigation via the BottomNavigationView for top level destinations in the app. However, many apps, especially legacy Android code bases, still primarily use activities as their top level destinations. Here, we explore a potential solution using Shared Element Transition on the BottomNavigationView.

There are many reasons why migrating to fragment-based navigation can be a complex task. Sometimes, it isn’t feasible or practical to refactor an Android app that uses activity-based navigation. For instance, many legacy apps have activities that use different launch modes, deep linking logic, etc.

With apps that use activity-based navigation, migrating to the relatively newer BottomNavigationView can result in UI jank. For instance, each activity reachable by the BottomNavigationView launches a new activity, which in turn has to create a new BottomNavigationView each time it is launched. If we stick with the default activity transitions, this can result in the BottomNavigationView seeming to jump into view with every activity transition. Ideally, we’d like the BottomNavigationView to be “sticky”, or at least give the illusion of it persisting across activities.

In this article, I introduce a potential solution to migrate to BottomNavigationView navigation for apps that are heavily activity based.

Shared element transition is not new. It was introduced in Android Lollipop. It’s used for animating transitions of views when switching between activities. For instance, take this classic example from the Android developer documentation where an ImageView and a TextView are the shared elements between the two screens.

shared element transitions

Exploring our options

1. A hack?

There is a hacky solution, but it uses overridePendingTransitions(0, 0), which essentially abolishes all activity transition animations. This means that while the BottomNavigationBar visually appears to be sticky, navigating between each activity looks abrupt, each activity snapping into view without any easing. While this is an easy solve, it may not produce the desired result, as seen in the video below.

overridePendingTransition(0,0) removes all activity transitions

2. Proposed solution using Shared Element Transition

What if we used activity transitions with shared elements on the BottomNavigationBar? If we think about it, it makes some sense. The common or shared element between the activities is the BottomNavigationBar itself. Although we’re not necessarily interested in animating the BottomNavigationBar in any way, it is the common or shared element between the activities. It turns out that this solution is potentially viable for projects that cannot migrate, or need to defer migration to fragment-based bottom navigation. Let’s get started.

Implementation

First, add the following attributes to your app theme. windowEnterTransition and windowExitTransition are only required if you want to override the default window transitions provided by the Android system. If you’re not interested in changing those, you can leave these out. The windowSharedElementEnterTransition and windowSharedElementExitTransition values are not really important here, since we’re not actually interested in animating any aspect of the BottomNavigationBar. However, we still need to specify this so that that the app understands that there is a shared element. You can use any of the provided standard transitions provided by the Android platform: change_bounds, change_image_transform, change_transform, change_image_transform, change_clip_bounds. You could also create a no-op transition class and use that if you wish.

<<style name="AppTheme" parent="android:Theme.Material">
<!-- enable window activity transitions (REQUIRED) -->
<item name="android:windowActivityTransitions">true</item>

<!-- specify enter and exit transitions (OPTIONAL) -->
<item name="android:windowEnterTransition">@transition/explode</item>
<item name="android:windowExitTransition">@transition/explode</item>

<!-- specify shared element transitions -->
<item name="android:windowSharedElementEnterTransition">
@transition/change_image_transform</item>
<item name="android:windowSharedElementExitTransition">
@transition/change_image_transform</item>
</style>

Depending on which standard transition you used, you’ll need to define it in your res/transition folder, for instance:

<!-- res/transition/change_image_transform.xml -->

<transitionSet xmlns:tools="http://schemas.android.com/tools"
tools:ignore="ResourceName">

<changeImageTransform/>
</transitionSet>

Next, define a shared element name for the widget, in our case the BottomNavigationView in your donottranslate.xml file.

<!-- res/values/donottranslate.xml -->

<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="nav_view_shared_element_transition_name">navigation_view_shared_element</string>
</resources>

Now, set that string as the android:transitionName attribute in your BottomNavigationView. You will see later why this is necessary

<!-- res/layout/activity_main.xml -->

<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/container_main"
android:layout_width="match_parent"
android:layout_height="match_parent"

<!-- Rest of your activity content -->


<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"
android:transitionName="@string/nav_view_shared_element_transition_name"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/bottom_nav_menu" />

</ConstraintLayout>

Now, we are ready to use the above to navigate using our BottomNavigationView.

Whenever you start a new activity from tapping on the BottomNavigationBar, you will need to set up the scene transition animation for the BottomNavigationBar. Note that I am using the base class NavigationBarView here in case your app makes use of the NavigationRailView on landscape or larger screens.

fun NavigationBarView.startActivityWithNavBarSharedTransition(
activity:Activity,
intent: Intent
)
{
val options = ActivityOptions.makeSceneTransitionAnimation(
activity,
this,
activity.getString(R.string.nav_view_shared_element_transition_name)
).toBundle()
activity.startActivity(intent, options)
}

This is what your MainActivity could look like:

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

findViewById<NavigationBarView>(R.id.nav_view).apply {
selectedItemId = R.id.navigation_home
setOnItemSelectedListener {
when (it.itemId) {
R.id.navigation_notifications -> {
startActivityWithNavBarSharedTransition(
this@MainActivity,
Intent(applicationContext, NotificationsActivity::class.java)
)
true
}

R.id.navigation_dashboard -> {
startActivityWithNavBarSharedTransition(
this@MainActivity,
Intent(applicationContext, DashboardActivity::class.java)
)
true
}

R.id.navigation_home -> true
else -> false
}
}
}
}
}

And voila, the app gives the illusion that the BottomNavigationBar is sticky, and we’ve kept the system’s activity transitions intact:

BottomNavigationView shared element transition for activity navigation

GitHub

You can find the source code for the demo here: https://github.com/kelvinwatson/activity-based-bottom-navigation

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Kelvin Watson
Kelvin Watson

No responses yet

Write a response

Recommended from Medium

Lists

See more recommendations