Last active
June 20, 2022 20:44
-
-
Save racka98/1f328e195e604fbdd43d8deeb17d096e to your computer and use it in GitHub Desktop.
Bars Visibility utilities in Jetpack Compose. For cases when you want to hide a bottom navigation bar or top bar on a screen that does not need them.
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
/** | |
* The base properties and methods that each item will need. | |
* Just to make it easier to add more bars item that can need hiding. | |
* Eg. scroll bars, navigation rails, etc. | |
*/ | |
@Stable | |
interface BarVisibilityState { | |
val isVisible: Boolean | |
fun hide() | |
fun show() | |
} | |
/** | |
* The default bar visibility state implementation. | |
* The class is marked with @Parcelize to make it easier to save it into a bundle so that it | |
* survives configuration changes. This uses kotlin-parcelize. | |
* Without parceling this class you would have to implement your own Saver to be used with | |
* rememberSaveable{ }. | |
* You could also use kotlinx-serialize (@Serializable) for using in Compose Multiplatform or | |
* just make your own Saver. | |
*/ | |
@Parcelize | |
private class DefaultBarVisibilityState( | |
private val defaultVisibility: Boolean = true | |
) : BarVisibilityState, Parcelable { | |
private val _isVisible = mutableStateOf(defaultVisibility) | |
override val isVisible: Boolean by _isVisible | |
override fun hide() { | |
_isVisible.value = false | |
} | |
override fun show() { | |
_isVisible.value = true | |
} | |
private companion object : Parceler<DefaultBarVisibilityState> { | |
override fun create(parcel: Parcel): DefaultBarVisibilityState { | |
val isVisibleBool = BooleanArray(1) | |
parcel.readBooleanArray(isVisibleBool) | |
return DefaultBarVisibilityState(defaultVisibility = isVisibleBool[0]) | |
} | |
override fun DefaultBarVisibilityState.write(parcel: Parcel, flags: Int) { | |
parcel.writeBooleanArray(booleanArrayOf(_isVisible.value)) | |
} | |
} | |
} | |
/** | |
* The bars you want to change their visibility for. | |
* The items are of the interface [BarVisibilityState] for uniformity. | |
*/ | |
@Stable | |
interface BarsVisibility { | |
val topBar: BarVisibilityState | |
val bottomBar: BarVisibilityState | |
// StatusBar and NavBar items are useful for triggering immersive mode | |
val statusBar: BarVisibilityState | |
val navigationBar: BarVisibilityState | |
} | |
/** | |
* A remember function for [BarsVisibility]. It survives configuration changes | |
* It should be used at the top level Composable or where the root NavHost is located | |
* and should be passed down to child Composables as needed. | |
*/ | |
@Composable | |
fun rememberBarVisibility(): BarsVisibility { | |
val topBarState = rememberSaveable { DefaultBarVisibilityState() } | |
val bottomBarState = rememberSaveable { DefaultBarVisibilityState() } | |
val statusBarState = rememberSaveable { DefaultBarVisibilityState() } | |
val navigationBarState = rememberSaveable { DefaultBarVisibilityState() } | |
val barsVisibility: BarsVisibility by remember { | |
derivedStateOf { | |
object : BarsVisibility { | |
override val topBar: BarVisibilityState | |
get() = topBarState | |
override val bottomBar: BarVisibilityState | |
get() = bottomBarState | |
override val statusBar: BarVisibilityState | |
get() = statusBarState | |
override val navigationBar: BarVisibilityState | |
get() = navigationBarState | |
} | |
} | |
} | |
return barsVisibility | |
} |
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
@Composable | |
fun App() { | |
val navController = rememberNavController() | |
val barsVisibility = rememberBarVisibility() | |
Scaffold( | |
modifier = Modifier, | |
bottomBar = { | |
AnimatedVisibility( | |
visible = barsVisibility.bottomBar.isVisible, // Bottom Bar visibility used here | |
enter = slideInVerticallyFadeReversed(), | |
exit = slideOutVerticallyFadeReversed() | |
) { | |
ReluctBottomNavBar(navController = navController) | |
} | |
} | |
) { innerPaddings -> | |
NavHost( | |
modifier = Modifier, | |
navController = navController, | |
startDestination = Graphs.DashboardDestinations.route, | |
route = Graphs.RootDestinations.route | |
) { | |
// Dashboard | |
dashboardNavGraph( | |
navController = navController, | |
barsVisibility = barsVisibility | |
) | |
// Screen 2 | |
screen2NavGraph( | |
navController = navController, | |
barsVisibility = barsVisibility | |
) | |
// Screen 3 | |
screen3NavGraph( | |
navController = navController, | |
barsVisibility = barsVisibility | |
) | |
} | |
} | |
} | |
// Let's say you want to hide the bottom bar when you open the Seach page found in screen3NavGraph | |
fun NavGraphBuilder.screen3NavGraph( | |
navController: NavHostController, | |
barsVisibility: BarsVisibility | |
) { | |
navigation( | |
route = "uniqueRoute", | |
startDestination = "uniqueRoute" | |
) { | |
// Tasks Page | |
composable(route = "uniqueRoute") { | |
barsVisibility.bottomBar.show() // Show the bottom bar when on Tasks page | |
TasksScreen( | |
onBackClicked = { navController.popBackStack() } | |
) | |
} | |
// Search Page | |
composable(route = "uniqueRoute") { | |
barsVisibility.bottomBar.hide() // Hide the bottom bar | |
TasksSearchScreen( | |
onNavigateToDetails = { | |
navController.navigate("detailsUniqueRoute") | |
}, | |
onBackClicked = { navController.popBackStack() } | |
) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment