See it Before You Build It, Mastering Jetpack Compose Previews
By Gemma Lara Savill
Published at April 6, 2024
Jetpack Compose empowers Android developers to create stunning apps faster, thanks to its Kotlin-based, declarative, and state-driven nature. But the real game-changer is previews.
With previews, you can see your UI updates in real time as you modify your code. No more compiling and restarting the app! If you have a Composable Preview defined, you can open the Preview panel on the top right of your Android Studio window.
Here you can see highlighted in red the Preview panel and the viewing options. In the latest Android Studio, you have three types of Preview options: List, Grid, and Gallery.
Preview your Android apps UI with Compose Previews
Here are three main ways you can create your previews.
1. The original @Preview annotation
Just adding this tag to a Composable function will make your Composable show up in the design view of this file. And you will get live updates as you make your edits.
You can define your Previews, adding parameters to define size, background, and even locale to see your previews with different text languages.
If you control + click on the @Preview annotation you can see all the available parameters.
@Repeatable
annotation class Preview(
val name: String = "",
val group: String = "",
@IntRange(from = 1) val apiLevel: Int = -1,
val widthDp: Int = -1,
val heightDp: Int = -1,
val locale: String = "",
@FloatRange(from = 0.01) val fontScale: Float = 1f,
val showSystemUi: Boolean = false,
val showBackground: Boolean = false,
val backgroundColor: Long = 0,
@UiMode val uiMode: Int = 0,
@Device val device: String = Devices.DEFAULT,
@Wallpaper val wallpaper: Int = Wallpapers.NONE,
)
Even better, use the @Device annotation to directly preview your composable on different virtual devices. Simply control-click (or right-click on macOS) on the annotation to see a list of available devices.
import androidx.annotation.StringDef
/**
* List with the pre-defined devices available to be used in the preview.
*/
object Devices {
const val DEFAULT = ""
const val NEXUS_7 = "id:Nexus 7"
const val NEXUS_7_2013 = "id:Nexus 7 2013"
const val NEXUS_5 = "id:Nexus 5"
const val NEXUS_6 = "id:Nexus 6"
const val NEXUS_9 = "id:Nexus 9"
const val NEXUS_10 = "name:Nexus 10"
...
}
The @UIMode annotation goes well beyond just Light and Dark
@IntDef(
value = [
UI_MODE_TYPE_MASK,
UI_MODE_TYPE_UNDEFINED,
UI_MODE_TYPE_APPLIANCE,
UI_MODE_TYPE_CAR,
UI_MODE_TYPE_DESK,
UI_MODE_TYPE_NORMAL,
UI_MODE_TYPE_TELEVISION,
UI_MODE_TYPE_VR_HEADSET,
UI_MODE_TYPE_WATCH,
UI_MODE_NIGHT_MASK,
UI_MODE_NIGHT_UNDEFINED,
UI_MODE_NIGHT_NO,
UI_MODE_NIGHT_YES
]
)
annotation class UiMode
Here you can see an example of what a regular Preview annotation can look like in Android Studio.
While the Preview code itself might be a bit longer, it offers a significant amount of flexibility for customizing how you see your composable.
2. Extract your most used @Preview annotations to create your own annotations
While defining a Composable Preview offers flexibility, some configurations might be repetitive across your project. For example, you might always want to preview your composables in both Dark and Light themes.
To handle these repetitive configurations, you can leverage the power of Jetpack Compose annotations. Here's how to create a custom annotation class specifically for theming your previews:
package com.gemma.previewsexample.ui.utils
import android.content.res.Configuration
import androidx.compose.ui.tooling.preview.Preview
@Preview(
name = "LightMode",
uiMode = Configuration.UI_MODE_NIGHT_NO,
showBackground = true,
group = "UIMode"
)
@Preview(
name = "DarkMode",
uiMode = Configuration.UI_MODE_NIGHT_YES,
showBackground = true,
group = "UIMode"
)
annotation class LightAndDarkPreview
Now you can consume your newly created annotation like this:
@LightAndDarkPreview
@Composable
private fun CustomPreview() {
PreviewsExampleTheme {
CustomPreviewScreen()
}
}
Here you can see the result in Android Studio
One line of code to show your dark and light previews, nice!.
3. New out-of-the-box Multipreview API templates
The new library androidx.compose.ui:ui-tooling-preview 1.6.+ introduces Multipreview API templates.
If you are using Jetpack Compose BOM (Bill Of Materials), this dependency is already included and ready to use in the 2024.01.00 version.
You can see the B.O.M to library mapping on this page Android Developers - BOM to library version mapping
If you are not using B.O.M. in your app's module build.gradle you can add the dependency
dependencies {
debugImplementation ("androidx.compose.ui:ui-tooling-preview:1.6.4")
}
If you are using the Gradle version catalog feature, add it you your libs.versions.toml
[versions]
compose-ui-tooling-preview = "1.6.4"
[libraries]
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose-ui-tooling-preview" }
And then import from the gradle file
dependencies {
debugImplementation(libs.compose.ui.tooling)
}
Templates like @PreviewScreenSizes, @PreviewFontScales, @PreviewLightDark, and @PreviewDynamicColors let you preview your composable across various configurations with a single annotation. This saves time and keeps your preview code clean.
To use them, simply start typing @Prev above your preview composable, and Android Studio's autocomplete will suggest these templates alongside standard options.
@PreviewScreenSizes
@Composable
private fun MultiPreview() {
PreviewsExampleTheme {
MultiPreviewScreen()
}
}
For instance, the @PreviewLightDark template replaces the need for a custom annotation to preview your composable in both Light and Dark themes, as mentioned earlier.
The @PreviewFontScale preview type is interesting to me, particularly when used in conjunction with the locale parameter. Given that text lengths can vary significantly across different languages, combining this with varying font sizes can lead to unexpected layout outcomes. This feature provides a valuable tool for gaining a rapid overview of potential layout issues, enabling early detection and resolution.
Here is an example of @PreviewFontScale with the default options. You can see the preview of the layout with the font scaled at different percentages:
And here you have the @PreviewScreenSizes in action
And the PreviewDynamicColors, this annotation is particularly useful when you’ve enabled dynamic color in your app.
Jetpack Compose previews are a developer's dream! They let you see your UI come to life before building and deploying the app. This translates to significant time savings.
To delve deeper, I created a project exploring the different preview options available. Feel free to check it out!
JetpackComposePreviewLab GitHub Project
The approach you take with previews depends on your project stage.
- For a quick look at individual composables, a simple @Preview annotation suffices.
- Once you have a full-screen layout, leverage advanced previews like @PreviewFontScale and @PreviewScreenSizes to see how your UI performs on different devices and configurations.
By the way, you can create your own Android Bot here: Create your own Android Bot