-
-
Save chrisbanes/ab31bf7b67b77948157687af010f0667 to your computer and use it in GitHub Desktop.
Compose SystemUI helper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright 2020 The Android Open Source Project | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
class SampleActivity : AppCompatActivity() { | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
setContent { | |
val systemUiController = remember { SystemUiController(window) } | |
Providers(SystemUiControllerAmbient provides systemUiController) { | |
MyApp() | |
} | |
} | |
} | |
} | |
@Composable | |
fun MyApp() { | |
val sysUiController = SystemUiControllerAmbient.current | |
// This will set the system bars background color (status and navigation bars) | |
// to be the surface color, and update the foreground to match (light/dark icons). | |
// If running on a API level where dark foreground isn't available, the background | |
// color will be transformed to maintain contrast. | |
sysUiController.setSystemBarsColor( | |
color = MaterialTheme.colors.surface | |
) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright 2020 The Android Open Source Project | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package com.example.compose.utils | |
import android.os.Build | |
import android.view.View | |
import android.view.Window | |
import androidx.compose.staticAmbientOf | |
import androidx.ui.graphics.Color | |
import androidx.ui.graphics.compositeOver | |
import androidx.ui.graphics.luminance | |
import androidx.ui.graphics.toArgb | |
/** | |
* A helper class for setting the navigation and status bar colors for a [Window], gracefully | |
* degrading behavior based upon API level. | |
*/ | |
class SystemUiController(private val window: Window) { | |
/** | |
* Set the status bar color. | |
* | |
* @param color The **desired** [Color] to set. This may require modification if running on an | |
* API level that only supports white status bar icons. | |
* @param darkIcons Whether dark status bar icons would be preferable. Only available on | |
* API 23+. | |
* @param transformColorForLightContent A lambda which will be invoked to transform [color] if | |
* dark icons were requested but are not available. Defaults to applying a black scrim. | |
*/ | |
fun setStatusBarColor( | |
color: Color, | |
darkIcons: Boolean = color.luminance() > 0.5f, | |
transformColorForLightContent: (Color) -> Color = BlackScrimmed | |
) { | |
val statusBarColor = when { | |
darkIcons && Build.VERSION.SDK_INT < 23 -> transformColorForLightContent(color) | |
else -> color | |
} | |
window.statusBarColor = statusBarColor.toArgb() | |
if (Build.VERSION.SDK_INT >= 23) { | |
@Suppress("DEPRECATION") | |
if (darkIcons) { | |
window.decorView.systemUiVisibility = window.decorView.systemUiVisibility or | |
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR | |
} else { | |
window.decorView.systemUiVisibility = window.decorView.systemUiVisibility and | |
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() | |
} | |
} | |
} | |
/** | |
* Set the navigation bar color. | |
* | |
* @param color The **desired** [Color] to set. This may require modification if running on an | |
* API level that only supports white navigation bar icons. Additionally this will be ignored | |
* and [Color.Transparent] will be used on API 29+ where gesture navigation is preferred or the | |
* system UI automatically applies background protection in other navigation modes. | |
* @param darkIcons Whether dark navigation bar icons would be preferable. Only available on | |
* API 26+. | |
* @param transformColorForLightContent A lambda which will be invoked to transform [color] if | |
* dark icons were requested but are not available. Defaults to applying a black scrim. | |
*/ | |
fun setNavigationBarColor( | |
color: Color, | |
darkIcons: Boolean = color.luminance() > 0.5f, | |
transformColorForLightContent: (Color) -> Color = BlackScrimmed | |
) { | |
val navBarColor = when { | |
Build.VERSION.SDK_INT >= 29 -> Color.Transparent // For gesture nav | |
darkIcons && Build.VERSION.SDK_INT < 26 -> transformColorForLightContent(color) | |
else -> color | |
} | |
window.navigationBarColor = navBarColor.toArgb() | |
if (Build.VERSION.SDK_INT >= 26) { | |
@Suppress("DEPRECATION") | |
if (darkIcons) { | |
window.decorView.systemUiVisibility = window.decorView.systemUiVisibility or | |
View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR | |
} else { | |
window.decorView.systemUiVisibility = window.decorView.systemUiVisibility and | |
View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv() | |
} | |
} | |
} | |
/** | |
* Set the status and navigation bars to [color]. | |
* | |
* @see setStatusBarColor | |
* @see setNavigationBarColor | |
*/ | |
fun setSystemBarsColor( | |
color: Color, | |
darkIcons: Boolean = color.luminance() > 0.5f, | |
transformColorForLightContent: (Color) -> Color = BlackScrimmed | |
) { | |
setStatusBarColor(color, darkIcons, transformColorForLightContent) | |
setNavigationBarColor(color, darkIcons, transformColorForLightContent) | |
} | |
} | |
/** | |
* An [androidx.compose.Ambient] holding the current [SystemUiController] or throws an error if none | |
* is [provided][androidx.compose.Providers]. | |
*/ | |
val SystemUiControllerAmbient = staticAmbientOf<SystemUiController> { | |
error("No SystemUiController provided") | |
} | |
private val BlackScrim = Color(0f, 0f, 0f, 0.2f) // 20% opaque black | |
private val BlackScrimmed: (Color) -> Color = { original -> | |
BlackScrim.compositeOver(original) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment