Get your android app ready for larger screen sizes using window-size classes on android
In this article, we are going to learn how to optimize our app to look better on every screen-sizes. It includes a phone, tablet and even a desktop (Chrome OS) and also learn why we need to consider optimizing our app for larger screens and more. Let’s begin.
Why do we need to support larger screen-sizes?
Android not only runs on smartphones, it also runs on Tablet, Desktop (Chrome OS), Foldables, Automotive and also on Smart TV’s with over three billion active devices. We are developers we ensure to provide a seamless experience on every platform, foldables are now the current hot topic is that every smartphone brand releases their own version of foldables. They dynamically change their screen sizes from a phone to a tablet-sized display.
How to support large screen-sizes?
To support every screen-size, we need to make our layout adaptive, so they adapt its size based on screen size. We achieve this by using window-size-classes on android. They provide high level abstraction of screen size by providing these simple types: compact, medium, and expanded, so we can easily make UI design decisions based on screen sizes. Ex: in compact we show a navigation bar or model navigation drawer, there are 2 types of window-size-classes
- Height
- Width
We usually consider width size class because most of the content in our app scrolls vertically.
To get the current window-size let’s add one dependency to our libs.versions.toml
[versions]
material3AdaptiveNavigationSuite = "1.3.0-beta04"
[libraries]
androidx-material3-adaptive-navigation-suite = { module = "androidx.compose.material3:material3-adaptive-navigation-suite", version.ref = "material3AdaptiveNavigationSuite" }
And define it on build.gradle.kts(module:app)
dependencies {
// NavigationSuiteScaffold
implementation(libs.androidx.material3.adaptive.navigation.suite)
}
Note: The material adaptive library is currently in beta. Check out the latest releases here
We have the two following benefits for adding this dependency
- One is obvious, we can access the window-size class for both height and width by using the currentWindowAdaptiveInfo() function.
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass.windowWidthSizeClass
So we can make UI design decisions about something like that.
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun App(
widthSizeClass: WindowWidthSizeClass
) {
// Perform logic on the size class to decide whether to show navigation rail or not.
val isExpanded = windowSizeClass == WindowWidthSizeClass.EXPANDED
Row {
if (isExpanded) {
NavigationRail {
NavigationRailItem(
/* ... */
)
}
}
DefaultNavGraph(/* ... */)
}
}
2. The second one is that we have access to NavigationSuiteScaffold which simplifies the navigation UI decision logic for us, based on window-size.
It shows the bottom navigation bar if the windowsize is in a compact or in a table-top (horizontal) position, and it shows navigation rail for everything else.
For what screen-size, which navigation layout is best ?
As per Material Design guidelines, window size class
- Compact (Width < 600 dp): Use Navigation bar, modal navigation drawer
- Medium (600 dp≤ width < 840 dp): Use Navigation rail, modal navigation drawer
- Expanded (840 ≤ width < 1200*): Use Navigation rail, modal or standard navigation drawer (for expanded use 2 pane layout if you use list-detail screen by using ListDetailPaneScaffold)
Note: ListDetailPaneScaffold is from a material-adaptive library which is currently in alpha, and it also is not supporting Navigation compose yet, for view-based app use SlidingPaneLayout.
Let’s see a real world demo
As I already mentioned, by using NavigationSuiteScaffold, it really simplifies our work. We don’t need to write a logic based on window-size-class ourselves. It does for us out of the box. Let’s get into a demo. Next, we also learn how to manually show navigation layout based on window-size-classes.
What do we build??
In this app we don’t focus on the content of the screen, instead just showing the text that displays, our current destination. Our goal is just displaying a navigation layout based on window-size.
Let’s implement it:
As we already added the required dependency, which is navigation-suite from material 3, so let’s focus on code.
For our top level destinations, I added an enum class. For that, here is that code.
enum class AppDestinations(
@StringRes val label: Int,
val icon: ImageVector,
@StringRes val contentDescription: Int
) {
HOME(R.string.home, Icons.Default.Home, R.string.home),
DRAWING(R.string.draw, Icons.Default.Draw, R.string.draw),
EDIT(R.string.edit, Icons.Default.Edit, R.string.edit),
SETTINGS(R.string.profile, Icons.Default.Person, R.string.settings),
}
And let’s call the NavigationSuiteScaffold and pass the necessary arguments
As you can see the code how easy it is to implement the navigation layout based on window-size class when we use NavigationSuiteScaffold, we don’t need to write. Single conditional statement for the window-size class
If you want, we can further customize it. If you want to show other navigation layout based on window-size, you can do so by passing another parameter in NavigationSuiteScaffold named layoutType.
val adaptiveInfo = currentWindowAdaptiveInfo()
/* Optional */
val customNavSuiteType = with(adaptiveInfo) {
if (windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.EXPANDED) {
NavigationSuiteType.NavigationRail
} else {
NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(adaptiveInfo)
}
}
Here we customize the navigation layout based on the window class. If we are currently on the EXPANDED screen, we show the navigation rail instead of the default navigation bar, our layout screen is considered as an EXPANDED if the below criteria meet:
- Phone in landscape
- Tablet in landscape
- Foldable in landscape (unfolded state)
- Desktop (Chrome OS)
Now we have learned how to work with NavigationSuiteScaffold. Now let’s move on to more customized option.
Handling navigation layout decisions ourselves by using Window-Size-Classes
Now let’s explore how to handle navigation layout based on Window-Size-Class ourselves.
As you can see in the code, we conditionally show Navigation Rail based on screen-size by using
val isExpanded = widthSizeClass == WindowWidthSizeClass.EXPANDED
Let’s call this function in MainActivity.kt
YourAppTheme{
val windowWidthSizeClass = currentWindowAdaptiveInfo().windowSizeClass
OsbApp(windowWidthSizeClass.windowWidthSizeClass) // here we using Width Size class.
}
When you run the app it shows an appropriate navigation layout based on widow-size
The source code of the NavigationSuiteScaffold demo is available on this repository:
In this article, we learned how to provide the best user-experience on larger screen sizes and also learned its use cases. I hope you will like this article. If so, please applause this story and share it with your friends and family. And i will see you in the next upcoming article with an interesting topic.
Signing off, Mubarak.M Basha