Exploring the Latest Jetpack Compose Preview — A Deep Dive into Android’s UI Toolkit

Syubban Fakhriya
5 min readApr 6, 2023

--

Jetpack Compose Preview

Recently, there have been some exciting new trends in Jetpack Compose development, including the release of Jetpack Compose Preview, a powerful tool that allows developers to see their UI changes in real time as they code. If you have ever built mobile apps using cross-platform frameworks like Flutter or React Native, you will be familiar with this functionality.

In this article, we will explore some of the latest trends in Jetpack Compose development and how the new Jetpack Compose Preview is changing the game for Android app development.

Preparation

First, we need to add the dependency to use compose preview

debugImplementation "androidx.compose.ui:ui-tooling:1.4.0"
implementation "androidx.compose.ui:ui-tooling-preview:1.4.0"

// this will enabled automatically when you initialize your project using compose template

Composable Preview Use Cases

(1) Simple Composable Preview

First, create a new composable function (Uppercase first letter and annotated with Composable).

@Composable
fun SimpleText(
text: String,
) {
Box(modifier = Modifier.background(Color.Cyan).padding(20.dp)) {
Text(
text = text,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.headlineMedium
)
}
}

Then create a new composable function again with a Preview annotation

@Composable
@Preview
fun SimpleTextPreview() {
VentNoteTheme {
Surface {
SimpleText(text = "Example Text")
}
}
}

Then press split to preview the change

Split view

The composable preview will look like this :

Simple Composable Preview

(2) Multiscreen Preview

We can create multiple screen previews using multiple preview annotations. This feature is useful when developing screens that need to be displayed differently on various device sizes such as phones, tablets, or TVs. To do so, follow the example below :

@Preview(showSystemUi = true, device = "id:Nexus 10")
@Preview(showSystemUi = true, device = "id:6.7in Foldable")
@Preview(showSystemUi = true, device = "spec:width=673.5dp,height=841dp,dpi=480")
@Composable
fun NotesPagePreview() {
NotesPage(
navHostController = rememberNavController(),
viewModel = NotesPageMockVM()
)
}

And the result will be like this (the complete source code is available on the repository at the end of the page ) :

Multiple screen

(3) And much more … (find more examples in the official documentation)

There are many more features that you can use in compose preview such as combined multipreview, dimension, background color, theme, locale, etc.

Compose Preview Action Menus

The Android preview layout feature comes with three main actions, there are animation preview, interactive mode, and run preview.

Action Menus

Animation Preview: Using this menu you can inspect animations defined using Jetpack Compose animation framework frame-by-frame. Current API that are supported are updateTransition , AnimatedVisibility , and CrossFade.

Interactive Mode: Using this menu we can make a live preview of gestures like click events (in general you can touch, scroll, or simulate gesture action in this mode) :

Interactive Mode

Run Preview: Using this menu, we run individually composable in isolation mode on the testing device to see how that particular composable looks on a real device/emulator.

Compose Preview with Injected ViewModel / Contain ViewModel

There will be certain errors when we tend to preview compose a function that has viewModel (especially injected hiltViewModel) that makes previews not possible.

One possible solution, we can create an abstraction from viewModel and make two classes (real & mock ViewModel) that will implement the abstraction. Here is an example :

interface NotesPageBaseVM {
val noteList: LiveData<Result<List<NoteModel>>>
}
@HiltViewModel
class NotesPageVM @Inject constructor(
private val repository: NoteRepository
): ViewModel(), NotesPageBaseVM {
override val noteList: LiveData<Result<List<NoteModel>>> = liveData {
loader.postValue(true)
try {
emitSource(repository.getNoteList()
.onEach {
loader.postValue(false)
}
.asLiveData())
} catch (e: Exception) {
loader.postValue(false)
emit(Result.failure(e))
}
}
}
class NotesPageMockVM: ViewModel(), NotesPageBaseVM {
// or you can initialize with your data
override val noteList: LiveData<Result<List<NoteModel>>> = liveData {}
}

The preview will be passing a mock instance as its parameter like this and the preview will be rendered normally :

@Preview
@Composable
fun NotesPagePreview() {
NotesPage(
navHostController = rememberNavController(),
viewModel = NotesPageMockVM()
)
}

Here is the result we got when we don’t use a mock ViewModel or maybe use a real ViewModel :

Not passing viewModel instance (because optional parameter)
Passing real viewModel (it needs repository to be passed as a constructor because we use hilt it shouldn’t be necessary, or if use instance directly it will be a much boilerplate)

So, that was pretty cool, right? This is all the stuff related to Jetpack Compose Preview.

References and Links

Last Words

You can find the complete source code in my repository (please leave a like star button)

Thanks for reading this article. Don’t forget to clap👏/recommend as much as you can and also share 📤 with your friends. It means a lot to me.

Also, Let’s become friends on Linkedin or Instagram. See you in the next article!

--

--

Syubban Fakhriya

Software developer, empower IT for practical use, self-development enthusiast