Foldable Navigation Rail

Sorin Albu

Hello Android developers!

This week we’re excited to share with you a new library to make it easy to support Navigation Rail on foldable devices like Surface Duo.

One of the tricks when building mobile apps for Surface Duo devices is to avoid your UI being obscured by the hinge. Controls that aren’t aware of foldable devices may place elements “under” the fold area, making them hard to read and touch:

Surface Duo showing Navigation Rail sample

To avoid this typically requires custom code using the WindowInfoTracker from the Jetpack Window Manager, observing changes to the WindowLayoutInfo, and adjusting the layout accordingly.

To make things easier, the Dual-screen layout library contains a collection of components designed to automatically adapt to foldable devices, so no additional code is required.

Adding the NavigationRailView

Similar to the BottomNavigationView and the TabLayout, this component is a customized NavigationRailView from Google’s Material library. It is designed to display its child views in a way that will not interfere with the hinge found on foldable devices like Surface Duo.

The NavigationRailView can use the setMenuGravity() function to control how the destinations from the menu views will be grouped: Top, Center, or Bottom.
The view encapsulates an implementation of the WindowInfoTracker and for each of the above three cases it will try to reposition some of the buttons to avoid overlapping with the folding feature.

Surface Duo showing Navigation Rail sample

This can be accomplished either using the xml’s app:menuGravity attribute or using the setMenuGravity() Java function:


or Kotlin setter function:

  binding.navRailView.menuGravity = Gravity.TOP

A special case is if we want to position the button in the center. Here we have an extra option in the form of a function called arrangeButtons(startBtnCount, endBtnCount) that takes two parameters: startBtnCount telling how many buttons should be positioned on the top screen and endBtnCount telling how many buttons should be positioned on the bottom screen, respectively.

This example shows how to set the first five destinations on the top screen and last two on the bottom screen:


Surface Duo showing Navigation Rail sample

Animations and gestures

Keeping the tradition with other components, NavigationRailView also supports animations and fling gestures.

The position of the destinations can also be changed at runtime using the two methods described above. To make the transition more pleasant, a translation animation can be used. This option can be enabled or disabled by changing the useAnimation property from both xml and Java or Kotlin. By default, the value is set to true.

In addition to this, we can also set up a custom interpolator for the animation using the animationInterpolator property:

  binding.navRailView.animationInterpolator = AccelerateInterpolator()

By default, an instance of the AccelerateDecelerateInterpolator() is used.


The button’s position can also be changed at runtime using a swipe gesture on the component.

The component can detect a swipe up or down gesture and will change the gravity of the destinations to Gravity.TOP or Gravity.BOTTOM.

This feature can be turned on or off by using the allowFlingGesture. By default, it is set to true.

Resources and feedback

If you have any questions, or would like to tell us about your apps, use the feedback forum or message us on Twitter @surfaceduodev

Finally, join us live on Twitch on Friday at 11am (Pacific Time) to discuss the Navigation Rail, foldable user experiences, and any other Surface Duo developer questions you might have.


Discussion is closed.

Feedback usabilla icon