SystemBars allows you to configure the appearance of Android’s status bar and navigation bar, including their colors and content appearance. It enables edge-to-edge display with proper system bar styling.
SystemBars is Android-specific and currently only works on Android platforms. On other platforms, this component has no effect.
Usage
import com.nomanr.lumo.ui.components.native.SystemBars
import com.nomanr.lumo.ui.components.native.SystemBarsDefaults
@Composable
fun App() {
AppTheme {
SystemBars(
colors = SystemBarsDefaults.defaultColors()
)
// Your app content
MyAppContent()
}
}
Default Colors
Use theme-based default colors:
SystemBars(
colors = SystemBarsDefaults.defaultColors()
// Status bar: primary color
// Navigation bar: background color
)
Custom Colors
Set specific colors for status and navigation bars:
SystemBars(
colors = SystemBarColor(
statusBarColor = AppTheme.colors.primary,
navigationBarColor = AppTheme.colors.surface
)
)
Edge-to-Edge Display
SystemBars automatically enables edge-to-edge mode, making system bars transparent while adjusting the content color based on the provided colors:
@Composable
fun EdgeToEdgeApp() {
AppTheme {
// System bars become transparent
SystemBars(
colors = SystemBarColor(
statusBarColor = AppTheme.colors.background,
navigationBarColor = AppTheme.colors.background
)
)
Scaffold(
modifier = Modifier
.fillMaxSize()
// Content extends behind system bars
.systemBarsPadding() // Add padding to avoid overlap
) {
// Your content
}
}
}
Dynamic Colors
Change system bar colors based on scroll position or screen:
@Composable
fun DynamicSystemBars() {
var isScrolled by remember { mutableStateOf(false) }
SystemBars(
colors = SystemBarColor(
statusBarColor = if (isScrolled) {
AppTheme.colors.surface
} else {
AppTheme.colors.primary
},
navigationBarColor = AppTheme.colors.background
)
)
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
// Detect scroll and update isScrolled
}
}
Parameters
SystemBars
Configuration for system bar colors
SystemBarColor
Color used to determine status bar appearance (not the actual bar color in edge-to-edge mode)
Color used to determine navigation bar appearance (not the actual bar color in edge-to-edge mode)
SystemBarsDefaults
defaultColors()
@Composable () -> SystemBarColor
Returns default system bar colors using theme colors
colors(isStatusContentBarDark: Boolean, isNavigationContentBarDark: Boolean)
@Composable (Boolean, Boolean) -> SystemBarColor
Returns system bar colors based on content darkness
Content Appearance
The system automatically determines whether to use light or dark icons:
// Light icons on dark backgrounds
SystemBars(
colors = SystemBarColor(
statusBarColor = Color.Black, // Light icons
navigationBarColor = Color.DarkGray // Light icons
)
)
// Dark icons on light backgrounds
SystemBars(
colors = SystemBarColor(
statusBarColor = Color.White, // Dark icons
navigationBarColor = Color.LightGray // Dark icons
)
)
The component calculates luminance and chooses appropriate icon colors:
- Luminance < 0.5 → Light icons
- Luminance ≥ 0.5 → Dark icons
Screen-Specific Colors
@Composable
fun HomeScreen() {
SystemBars(
colors = SystemBarColor(
statusBarColor = AppTheme.colors.primary,
navigationBarColor = AppTheme.colors.background
)
)
// Home content
}
@Composable
fun SettingsScreen() {
SystemBars(
colors = SystemBarColor(
statusBarColor = AppTheme.colors.surface,
navigationBarColor = AppTheme.colors.surface
)
)
// Settings content
}
With Scaffold
@Composable
fun AppWithScaffold() {
SystemBars(
colors = SystemBarsDefaults.defaultColors()
)
Scaffold(
topBar = {
TopBar(
title = { Text("My App") },
backgroundColor = AppTheme.colors.primary
)
},
bottomBar = {
NavigationBar {
// Navigation items
}
}
) { paddingValues ->
Box(modifier = Modifier.padding(paddingValues)) {
// Content
}
}
}
Transparent Bars
For immersive experiences:
@Composable
fun ImmersiveScreen() {
// Determine bar colors from content
val topContentColor = AppTheme.colors.background
val bottomContentColor = AppTheme.colors.surface
SystemBars(
colors = SystemBarColor(
statusBarColor = topContentColor,
navigationBarColor = bottomContentColor
)
)
Box(modifier = Modifier.fillMaxSize()) {
// Full-screen image or video
Image(
painter = painterResource("background.jpg"),
contentDescription = null,
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Crop
)
// Content with proper padding
Column(
modifier = Modifier
.fillMaxSize()
.systemBarsPadding()
) {
// Your content
}
}
}
Dark Mode Support
@Composable
fun ThemeAwareSystemBars() {
val isDark = isSystemInDarkTheme()
AppTheme(isDarkTheme = isDark) {
SystemBars(
colors = if (isDark) {
SystemBarColor(
statusBarColor = Color.Black,
navigationBarColor = Color.Black
)
} else {
SystemBarColor(
statusBarColor = Color.White,
navigationBarColor = Color.White
)
}
)
// App content
}
}
Best Practices
- Call Early: Place SystemBars at the top level of your composition
- Consistent Colors: Match system bar colors to adjacent UI elements
- Dark Mode: Test both light and dark themes
- Contrast: Ensure sufficient contrast between content and bars
- Transitions: Animate color changes for smooth transitions
- Insets: Use
systemBarsPadding() to avoid content overlap
- Screen Specific: Update colors when navigating between screens
- Android: Full support (API 21+)
- iOS: Not applicable (iOS manages status bar differently)
- Desktop: Not applicable (no system bars)
- Web: Not applicable (no system bars)
Implementation Details
Under the hood, SystemBars:
- Enables edge-to-edge display using Android’s
enableEdgeToEdge()
- Sets system bars to transparent
- Adjusts icon colors based on the luminance of provided colors
- Uses
SystemBarStyle.dark() for light icons
- Uses
SystemBarStyle.light() for dark icons
Troubleshooting
Content Hidden Behind Bars
// Add system bars padding
Box(
modifier = Modifier
.fillMaxSize()
.systemBarsPadding() // ✓ Correct
) {
// Content
}
Wrong Icon Colors
// Ensure color values match your UI
SystemBars(
colors = SystemBarColor(
statusBarColor = actualTopBarColor, // Use actual color
navigationBarColor = actualBottomBarColor
)
)
Not Working on Device
Ensure you’re using ComponentActivity:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AppTheme {
SystemBars(/* ... */)
// Content
}
}
}
}
Source Reference
See the full implementation in SystemBars.kt:16-56 (Android) and SystemBarsDefaultInsets.kt (insets utilities).