3

I've implemented the pinned top app bar scroll container, and it works for changing the app bar color on scroll, however the status bar color isn't affected at all.

Here's what I have:

val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())

Scaffold(
    Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
    topBar = {
        // just a wrapper for CenterAlignedTopAppBar
        StandardTopAppBar("Home", scrollBehavior = scrollBehavior)
    }
){ ... }

If it's relevant, in order to detect if the soft keyboard is present, I enabled:

WindowCompat.setDecorFitsSystemWindows(window, false)

And my status bar color in initially set in my Theme. It was set to primary color when I autogenerated the project in android studios, but I changed it to surface color to match the appbar standards:

if (!view.isInEditMode) {
        SideEffect {

            (view.context as Activity).window.statusBarColor = colorScheme.surface.toArgb()
            //(view.context as Activity).window.statusBarColor = colorScheme.primary.toArgb()
            ViewCompat.getWindowInsetsController(view)?.isAppearanceLightStatusBars = !darkTheme // changed from just darkTheme
        }
    }

tl;dr; top app bar color changes on scroll, but status bar does not. What is the correct pattern to use here? I looked through some of the pinnedScrollBehavior code, and I don't see anything that would invoke status bar changes, so I'm wondering if I'm supposed to have the status bar be transparent and change the insets for the appbar? Or should I manually hook into the scroll logic and change the color myself? Any help is appreciated!

Nathan
  • 73,987
  • 14
  • 40
  • 69

1 Answers1

5

In Theme.kt, inside the YourAppTheme() function add.

WindowCompat.setDecorFitsSystemWindows(window, false)

Doing this will display contents below StatusBar and NavigationBar* ( Only on older versions of Jetpack Compose. In newer versions, PaddingValues are correctly set by default. ).

Now set the StatusBar and NavigationBar color to Color.Transparent.

// make sure to use the compose color package, not the default one
import androidx.compose.ui.graphics.Color

window.statusBarColor = Color.Transparent.toArgb()
window.navigationBarColor = Color.Transparent.toArgb()

You also need to make sure that the padding values for the direct child of Scaffold() are correctly set using the padding values passed in the callback from the Scaffold() composable.

Set the correct StatusBar and NavigationBar icon colors for the theme.

WindowCompat.getInsetsController(window, window.decorView).isAppearanceLightStatusBars = !darkTheme

WindowCompat.getInsetsController(window, window.decorView).isAppearanceLightNavigationBars = !darkTheme

If you're using ModalBottomSheetLayout or BottomSheetScaffold, you also need to set Insets inside your BottomSheet composable to prevent NavigationBar from overlapping app content using,

Modifier.windowInsetsPadding(WindowInsets.navigationBars)

Edit

In Material3, window.setDecorFitsSystemWindows() is only compatible > API Level 30.

Use WindowCompat.setDecorFitsSystemWindows(window, false) for backwards compatibility.

Amal
  • 328
  • 2
  • 8
  • Is the top appbar *supposed* to be under the status bar, or is the top app bar scroll behavior supposed to hook into status bar color automatically, or am I supposed to do that manually? – Nathan Nov 27 '22 at 00:36
  • edit: I apologize, I missed the `Color.Transparent` section of your answer. I've set that now (well, `Color.TRANSPARENT` which I assume is the same), and it did *something*, but not what I wanted. It looks like it sets my color to the Primary theme color (a sort of light pink in my case) and not the surface color (a very dark gray, that the appbar wants to be). The status bar color still does not change when I scroll the content, like the appbar color does. – Nathan Nov 27 '22 at 00:41
  • 1
    AppBar isn't under the StatusBar since the insets are correctly set and passed by default in the recent versions of Jetpack Compose. Did you set the color of StatusBar and Navigation Bar to Color.Transparent? For me, not setting that makes the statusbar gray. – Amal Nov 27 '22 at 00:43
  • Ah, I made a stupid mistake-- when commenting out the logic which set the status bar to surface color, I accidentally uncommented my logic which set the color to primary. I've disabled that, and it's working! It looks great, thank you so much. – Nathan Nov 27 '22 at 00:44
  • 1
    Great. I edited the answer making it easier to not miss those lines. – Amal Nov 27 '22 at 00:46
  • 1
    This is starting to make more sense! My top level scaffold defined a bottom app bar, but not a top app bar—I defined that in scaffolds on each of my screens (and use a non-padded top level appbar of the same color to prevent flicker). It seems like scaffold was expecting that though, so the `innerPadding` it gave me was wrong, and I was ignoring the padding and just setting bottom app bar padding. Now, I set `contentWindowInsets = ScaffoldDefaults.contentWindowInsets.exclude(WindowInsets.statusBars),` within my Scaffold and I can leverage the padding correctly! – Nathan Nov 27 '22 at 00:55
  • 1
    I had one issue that stemmed from this, which is separate enough that I made another question, but related enough that I wanted to comment it here— [take a look at it](https://stackoverflow.com/questions/74598012/jetpack-compose-top-app-bar-pinnedscrollbehavior-not-changing-color-on-scroll-f) if you have time. – Nathan Nov 28 '22 at 08:43