Custom TopAppBar using Android Jetpack Compose

Shiva Thapa
5 min readJun 29, 2024

--

When building modern android apps, I am sure you have came across different problem with the TopAppBar composable when complimenting design or user experience.

Some problems may be:

  • We cannot use SearchBar in TopAppBar (it does not get along).
  • We cannot customize height of the TopAppBar.
  • We cannot define other composable that surpasses default height i.e. use only Text composable. (Of course only Text composable is recommended as the parameter is itself named “title”)

Here is a little reference about the “title” parameter I talked about:

fun TopAppBar(
title: @Composable () -> Unit,
modifier: Modifier = Modifier,
navigationIcon: @Composable () -> Unit = {},
actions: @Composable RowScope.() -> Unit = {},
windowInsets: WindowInsets = TopAppBarDefaults.windowInsets,
colors: TopAppBarColors = TopAppBarDefaults.topAppBarColors(),
scrollBehavior: TopAppBarScrollBehavior? = null
) { ... }

Why do we exactly need to customize TopAppBar? Is it that necessary? Can’t we just customize composable in the body of Scaffold and don’t use TopAppBar(topBar)?

I will answer all these with context. Here, let’s start,

Take a look at the gif below, what did you see there? Is there any way to improve the experience?
I know it’s Google, and I admire the developers work here, but still I would love the transparent container color for the TopAppBar instead of that extra colored padding around the SearchBar. (let’s ignore the statusBar color and padding here)

Search bar of Gmail app

You may be thinking that’s a simple fix, code like below will fix it. But, the problem is, it does not get along that easy. You’ll see unexpected behavior and get stuck with the topAppBar height limitation for the SearchBar when it expands.

  // Argument for TopAppBar
colors = TopAppBarDefaults.topAppBarColors().copy(
containerColor = Color.Transparent,
scrolledContainerColor = Color.Transparent,
)

Expectation vs what we got, (also look at the list behind the SearchBar below vs Gmail)

Expected vs Got (searchBar does not expand)

Maybe using the SearchBar inside the “content” of the TopAppBar may seem to be a good approach. But managing scrollState, and controlling the scrollBehavior is more tedious task and can be neck breaking.

Scaffold already provides us with topBar which can be used with TopAppBar composable with scrollBehavior, why bother using body content for the same.

The above we discussed is only case for the SearchBar, what about the custom component that you want to use? something like the banner, or any other Composables like brand name highlights.

The best thing about the TopAppBar is that it manages scrollBehavior and it has many behavior that we can adapt to. Like,

  • enterAlwaysScrollBehavior
  • pinnedScrollBehavior
  • exitUntilCollapsedScrollBehavior, etc.

Because of these, it’s easier to use nestedScroll to control the topBar (TopAppBar) behavior. All thanks to the developers behind this!

Now, let’s talk about solution,

I tried to use different techniques, and searched for very long time to find a way to get the desired result, but I was not getting the expected behavior. Finally, after a long time I came across this article written by Oya Canlı where she describes the problem she faced with the default TopAppBar, and how she modified the code to meet the desired behavior while taking benefits from built-in scrollBehaviors of TopAppBar.

To summarize, Miss Oya Canlı created a custom FlexibleTopBar that allows for more customization (i.e. use of any Composable) while supporting various scrollBehaviors.

This solution opened countless use case of the topBar where you can use custom composable and still take advantage of TopAppBar’s scrollBehavior.

(Remember, “topBar” is the Scaffold’s parameter which commonly takes TopAppBar composable argument with scrollBehavior.)

If you’re familiar with the TopAppBar composable then you’ll find no difference in the custom TopAppBar(i.e. FlexibleTopBar from Oya Canlı). The title, navigationIcon, actions are now replaced by the content which takes composable and provides more flexibility.
Here’s the code snippet,

@Composable
fun CustomFlexibleTopAppBar(
modifier: Modifier = Modifier,
colors: FlexibleTopBarColors = FlexibleTopBarDefaults.topAppBarColors(),
scrollBehavior: TopAppBarScrollBehavior? = null,
content: @Composable () -> Unit,
) { ... }

Let me help you with the parameters,

  • color: Custom color class i.e. FlexibleTopBarColors that will be used to resolve the colors used for this top app bar in different states.
  • scrollBehavior: It adjusts topBar height and colors based on how much the content is scrolled. This makes the top bar change its appearance dynamically as you scroll through the app’s content. (default behavior)
  • content: The composable content that we want to use in topBar of Scaffold. (the content that we’ve been trying to draw in topBar)

Below are the examples in which it is used. There are many possibility with this custom FlexibleTopAppBar composable.

Use of the custom code for topBar.

If you like the complete code then you can refer to the file or follow the article.
For complete app, checkout this repository.

I’d like to extend a special thank you to Oya Canlı for her article, which served as a valuable reference for this piece.

Thank you for visiting!

Don’t forget, there is always better way to do it!

--

--