I want to implement transparent status bar in jetpack compose.
I have integrated the Accompanist library for this but it has no transparent effect on status bar.
implementation "com.google.accompanist:accompanist-systemuicontroller:0.18.0"
// Remember a SystemUiController
val systemUiController = rememberSystemUiController()
val useDarkIcons = !isSystemInDarkTheme()
DisposableEffect(systemUiController, useDarkIcons) {
// Update all of the system bar colors to be transparent, and use
// dark icons if we're in light theme
systemUiController.setStatusBarColor(
color = Color.Transparent,
darkIcons = useDarkIcons
)
// setStatusBarColor() and setNavigationBarColor() also exist
onDispose {}
}
Tried this as well, but it has problem with the gesture navigation
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
val window = (view.context as Activity).window
val insets = WindowCompat.getInsetsController(window, view)
window.statusBarColor = Color.Transparent.toArgb() // choose a status bar color
window.navigationBarColor = Color.Transparent.toArgb() // choose a navigation bar color
insets.isAppearanceLightStatusBars = !useDarkTheme
insets.isAppearanceLightNavigationBars = !useDarkTheme
}
}
Kindly suggest a better solution for the transparent status bar.
You have to enable full-screen mode to draw under statusbar:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
}
And you can use WindowInsets to avoid drawing under "System gestures":
ViewCompat.setOnApplyWindowInsetsListener(view) { view, windowInsets ->
val insets = windowInsets.getInsets(
WindowInsetsCompat.Type.systemGestures()
)
view.updatePadding(
insets.left,
insets.top,
insets.right,
insets.bottom
)
WindowInsetsCompat.CONSUMED
}
For more information, look at the documentation
Try This
Add the below line to your Theme
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
after adding this line to the theme set this theme in your activity in which you want to set a transparent status bar
Your activity/container layout you wish to have a transparent status bar needs this property set:
android:fitsSystemWindows="true"
add in activity root layout
Related
I have a screen, which contains a Map and I want to make a statusBar completely transparent.
What I've tried:
implementation "com.google.accompanist:accompanist-systemuicontroller:0.26.1-alpha"
#Composable
fun MapMainScreen() = Column(
modifier = Modifier.fillMaxSize()
) {
val controller = rememberSystemUiController()
controller.setStatusBarColor(color = Color.Transparent)
controller.setNavigationBarColor(color = Color.Transparent)
controller.setSystemBarsColor(color = Color.Transparent)
Map()
}
Also, I've tried to play with window in MainActivity before and in setContent call:
WindowCompat.setDecorFitsSystemWindows(window, false)
window.setFlags(
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
)
I want to see a result like in Google Maps, but now my statusBar has a White-Gray color instead of Transparent
How can I fix this and make my statusBar Transparent?
Any additional dependency is not needed.
In your Compose theme (or directly in activity) set this:
SideEffect {
with(view.context as Activity) {
WindowCompat.setDecorFitsSystemWindows(window, false)
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme
window.statusBarColor = Color.Transparent.toArgb()
window.navigationBarColor = Color.Transparent.toArgb()
}
}
Optionally, you could also add this line to make the navigation bar transparent:
window.navigationBarColor = Color.Transparent.toArgb()
This is what Accompanist suggests in the doc:
// Remember a SystemUiController
val systemUiController = rememberSystemUiController()
val useDarkIcons = !isSystemInDarkTheme()
DisposableEffect(systemUiController, useDarkIcons) {
// Update all of the system bar colors to be transparent, and use
// dark icons if we're in light theme
systemUiController.setSystemBarsColor(
color = Color.Transparent,
darkIcons = useDarkIcons
)
// setStatusBarColor() and setNavigationBarColor() also exist
onDispose {}
}
Also the latest version is : 0.26.3-beta
I disabled fitSystemWindows via WindowCompat.setDecorFitsSystemWindows(window, false) to draw behind the status bar and I am using the insets accompanist library to get the respective insets for adding padding to specific composables.
However, if I show a fullscreen dialog, the dialog still has padding to the system- and navigation bar and refuses to draw behind the status bar.
The Dialog looks like the following snippet:
Dialog(
onDimissRequest = {},
properties = DialogProperties(usePlatformDefaultWidth = false)
) {
..
}
Is there any additional setting required in order to also let the dialog draw behind the system's status bar?
Maybe ModalDrawerLayout can help ?
ModalDrawerLayout(
drawerContent = {
// smth, idk
},
bodyContent = {
Dialog(
onDismissRequest = {},
properties = DialogProperties(usePlatformDefaultWidth = false)
) {
// Dialog content here
}
}
)
I'm using the Accompanist systemUiController library and I'm setting
darkIcons=false
while in Light Theme but the effect doesn't apply on devices with android 11. It seems to work on devices with android 10 for example.
This is the code with which I'm trying to set the colors.
val systemUiController = rememberSystemUiController()
systemUiController.setStatusBarColor(color=statusBarColor,darkIcons=false)
where statusBarColor is a darker color which represents the reason I want white foreground/icons
While in Dark Theme it works to set darkIcons
to both true and false and the effect applies accordingly
This is the status bar on LightTheme with darkIcons=false and darkIcons=true
This is the status bar on DarkTheme with darkIcons=false
This is the status bar on DarkTheme with darkIcons=true
For reference this is my whole Theme.kt
private val LightBase = ASBTheme(
material = lightColors(
background = FigmaPrimaryWhite,
onBackground = FigmaTextBlack,
surface = FigmaPrimaryWhite,
onSurface = FigmaTextBlack,
primary = FigmaSecondaryAvastBlue,
error = FigmaStatusPink,
),
textColorLabel = FigmaSecondaryAvastPurple,
colorAccent = FigmaPrimaryGreen,
... //bunch of custom colors
)
private val DarkBase = ASBTheme(
material = darkColors(
background = FigmaPrimaryBlackBg,
onBackground = FigmaTextWhite,
surface = FigmaSecondaryAvastBlueDark,
onSurface = FigmaTextWhite,
primary = FigmaSecondaryBlackDark,
error = FigmaStatusPink
),
textColorLabel = FigmaSecondaryAvastPurpleBright,
colorAccent = FigmaStatusGreen,
... //bunch of custom colors
)
private val LocalAsbTheme = staticCompositionLocalOf { LightBase }
var navBarColor: Color? = null
var statusBarColor: Color? = null
#Composable
fun ASBTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: #Composable () -> Unit
) {
val colors = if (darkTheme) {
DarkBase
} else {
LightBase
}
if (darkTheme) {
navBarColor = DarkBase.background
statusBarColor = DarkBase.primary
} else {
navBarColor = LightBase.background
statusBarColor = LightBase.primary
}
SetBarsTheme(statusBarColor!!, navBarColor!!)
CompositionLocalProvider(
LocalAsbTheme provides colors,
) {
MaterialTheme(
colors = colors.material,
content = content,
)
}
}
val MaterialTheme.asbTheme: ASBTheme
#Composable
#ReadOnlyComposable
get() = LocalAsbTheme.current
SetBarsTheme() is where I'm trying to set the status bar colors depending on the lifecycle event so that the colors would maintain after onPause() / onStop(). I also tried to set the colors outside of this logic and the bug still persists.
#Composable
fun SetBarsTheme(
statusBarColor: Color,
navigationBarColor: Color,
darkIcons:Boolean=false,
) {
val lifecycleOwner = LocalLifecycleOwner.current
val systemUiController = rememberSystemUiController()
DisposableEffect(lifecycleOwner) {
// Create an observer that triggers our remembered callbacks
// for sending analytics events
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_RESUME) {
systemUiController.setStatusBarColor(color=statusBarColor,darkIcons)
systemUiController.setNavigationBarColor(color=navigationBarColor)
}
}
// Add the observer to the lifecycle
lifecycleOwner.lifecycle.addObserver(observer)
// When the effect leaves the Composition, remove the observer
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
}
There's a fixed bug, make sure you're using the latest Accompanist version.
If you still able to reproduce it, you should report it, including used device/dependencies versions.
I'm using the new Material 3 NavigationBar and NavigationBarItem components, I want the NavigationBar to be thinner, because the default one is too large. I want one similar to the one Gmail or Drive has (see picture at the end for the comparison). Making the icon smaller doesn't work, and neither changing all the available paddings (Icon, NavigationBar and NavigationBarItem).
This is the Composable code, if I change the NavigationBar heigh (using Modifier) then this happens:
I primarly want to remove the space between the label and the bottom, and the one between the top and the icon.
#Composable
fun MyAppBottomBar(navController: NavController, tabs: Array<MenuBottom>) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route ?: MenuBottom.INICIO.route
val rutas = remember { MenuBottom.values().map { it.route } }
if (currentRoute in rutas) {
NavigationBar(containerColor = elevation01) {
tabs.forEachIndexed { index, item ->
NavigationBarItem(
selected = currentRoute == item.route,
onClick = {
if (item.route != currentRoute) {
navController.navigate(item.route) {
popUpTo(navController.graph.startDestinationId) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
}
},
label = { Text(stringResource(id = item.title)) },
icon = {
if (item.route == currentRoute) {
Icon(item.selectedIcon, contentDescription = null, tint = Color.Black)
} else {
Icon(item.unselectedIcon, contentDescription = null)
}
},
colors = NavigationBarItemDefaults.colors(
selectedIconColor = Color.Black,
unselectedIconColor = Color.Black,
indicatorColor = Greenyellow,
selectedTextColor = Color.Black,
unselectedTextColor = Color.Black
)
)
}
}
}
}
NavigationBar does not use padding. It uses a fixed height. How do I know that? While working with MUI (which is a React implementation of Material design) I found that they use a fixed height, and margin: auto to center items vertically. Then I figured jetpack compose NavigationBar might do the same and the idea was right. So whats the solution?
NavigationBar(
modifier = Modifier.height(64.dp)
) {...}
Or change it to your taste. It will shrink and grow the space taken up.
This most likely has to do with the bottom navigation. The grey bar you see has its own padding by default.
Have a look at this documentation on how to remove those System intents.
Here's what you need to do in a nutshell:
implementation "com.google.accompanist:accompanist-insets:<version>"
Then in your MainActivity call WindowCompat.setDecorFitsSystemWindows(window, false) like this:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
setContent {...}
}
Now your App should use the entire Screen and your NavigationBar should have the same height as the one from Gmail.
To apply single ones of them again e.g. StatusBar call a modifier:
Modifier.statusBarsPadding()
In Jetpack Compose, TopAppBar shows default background color irrespective of what we added to themes.xml.
So how can we change TopAppBar background color from themes.xml so it's applied globally to the App?
TopAppBar(
title = { Text("Activity") },
navigationIcon = {
IconButton(onClick = { onBackPressed() }) {
Icon(Icons.Filled.ArrowBack, contentDescription = null)
}
}
)
themes.xml
<style name="Theme.MyApplication" parent="Theme.MaterialComponents.DayNight">
<!-- Primary brand color. -->
<item name="colorPrimary">#android:color/black</item>
<item name="colorPrimaryVariant">#android:color/holo_orange_dark</item>
<item name="colorOnPrimary">#android:color/white</item>
</style>
Note : we can change it through backgroundColor attribute of TopAppBar but here I want to achieve it globally.
The accepted answer explains what to do adequately. There is one thing you might need to keep in mind, though.
TopAppBar uses MaterialTheme.colors.primarySurface as the background color, and it's defined as the following.
[androidx/compose/material/Colors.kt]
val Colors.primarySurface: Color get() = if (isLight) primary else surface
In other words, if the device is in the light mode, it uses primary, and in the dark mode, it uses surface.
Suppose I have a theme with everything as default values.
private val DarkColorPalette = darkColors()
private val LightColorPalette = lightColors()
#Composable
fun ComposeTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: #Composable () -> Unit) {
val colors = if (darkTheme) {
DarkColorPalette
} else {
LightColorPalette
}
MaterialTheme(
colors = colors,
typography = Typography,
shapes = Shapes,
content = content
)
)
lightColors and darkColors have the following values by default.
fun lightColors(
primary: Color = Color(0xFF6200EE),
...
)
fun darkColors(
surface: Color = Color(0xFF121212),
...
)
When the device is in the light mode, primary (0xFF6200EE) will be TopAppBar's background color.
But when the device is in the dark mode, surface (0xFF121212) is not TopAppBar's background color. It's slightly lighter; 0xFF282828 to be exact.
The reason is TopAppBar has a built-in elevation, which is 4.dp by default.
[androidx/compose/material/AppBar.kt]
#Composable
fun TopAppBar(
...
elevation: Dp = AppBarDefaults.TopAppBarElevation // 4.dp
) {
This most likely won't cause a problem, but it might matter if you want to apply the exactly same background color to somewhere else, such as setting the same color for the status area's background.
val systemUiController = rememberSystemUiController()
systemUiController.setSystemBarsColor(color = Color(0xFF282828))
Note that for this particular case, it would be easier if you just go full screen and add padding at the top.
WindowCompat.setDecorFitsSystemWindows(window, false)
setContent {
MyAppTheme {
Surface(
modifier = Modifier.systemBarsPadding().fillMaxSize(), // <--
) {
...
}
}
}
For the TopAppBar and the other composables the basis of theming is the MaterialTheme composable and not the AppCompat/MaterialComponents XML themes.
The TopAppBar uses the backgroundColor attribute.
The default value is defined by MaterialTheme.colors.primarySurface.
You can change these colors globally defining your theme adding your Colors and passing them to a MaterialTheme:
private val LightColors = lightColors(
primary = Yellow500,
//...
)
Otherwise you can simply use :
TopAppBar(
title = { Text("Activity") },
backgroundColor = /*...*/,
/* ... */
)
If you want to use the AppCompat XML themes in Jetpack Compose you can use the AppCompat Compose Theme Adapter provided by the accompanist library.
When you create a new project in studio, you get a file named Theme.kt, in which there are color palettes named lightColors and darkColors. You should modify the parameters of those values to achieve the result globally in your app.