Reputation: 2476
Imagine the usual behavior of a toolbar in Android.
You define a Toolbar
widget in the Activity
, and can access it using onCreateOptionsMenu
and onOptionsItemSelected
inside your fragments.
However, something like this is not possible with normal Jetpack Compose, as there is no way of accessing the Toolbar
that is defined in the Activity
's Scaffold
.
So think of this scenario. You have an Activity
, with the Scaffold
defined in it, and a NavHost
inside that Scaffold
. The NavHost
contains all the sub-pages of your application (Other Composables). The title can be handled view the Navigation Destination Listener, what remains is the Actions of the Toolbar.
How would you change the toolbar actions depending on the current page/composables you're in? And handle clicks on these actions?
P.S : Using a Toolbar in each of the pages is not a solution, as it makes for a bad user experience when switching between animated pages, where the toolbar will disppear and reappear on each page.
Upvotes: 4
Views: 1785
Reputation:
I used an interface I named ToolbarController
which contained callback methods that could set the value for the variable(s) used in the the call to scaffold's TopAppBar
:
@Composable
fun MyApp(){
var toolbarTitle by remember{ mutableStateOf("") }
// ToolbarController would be some interface you have defined
val toolbarController = object: ToolbarController {
override fun setTitle(title: String){
toolbarTitle = title
}
}
Scaffold(
topBar = {
TopAppBar( title = { Text(text = toolbarTitle) } )
}
){
SomeScreen(toolbarController = toolbarController)
}
}
@Composable
fun SomeScreen(
toolbarController: ToolbarController
) {
//I'm not 100% sure I need to use an effect here, but I think so...
//And I'm not sure this is the right one. It is not a coroutine I call,
//but it of course works with normal calls. Also SideEffect runs on every
//recompose according to the docs, and that's not what we want.
//https://developer.android.com/jetpack/compose/side-effects
LaunchedEffect(true){
toolbarController.setTitle("Some screen title")
}
}
Edit: And it is easy to use it for any of the toolbar properties, you could create the interface like this:
interface ToolbarController{
fun configToolbar(
title: String = "",
navigationIcon: IconButton? = null,
actions: List<IconButton> = listOf()
)
}
The point is that you just make callback functions and run them in LaunchedEffect. That is one way to set toolbar properties from within a composable in the scaffold. The interface stuff is just a way to group these callbacks so it don't get too messy.
Upvotes: 6
Reputation: 363785
You can use the TopAppBar
at a Scaffold
level and use your current destination to customize the topBar
.
Something like:
topBar = {
// Use your logic here
val currentDestination = navBackStackEntry?.destination
if (currentDestination == ....) {
CustomAppBar()
} else {
TopAppBar(
title = { /*...*/ },
actions = {
if (currentDestination == ....) {
IconButton(onClick = { /* doSomething() */ }) {
Icon(Icons.Filled.Favorite, contentDescription = "")
}
}
IconButton(onClick = { /* doSomething() */ }) {
Icon(Icons.Filled.Add, contentDescription = "")
}
}){ //... }
}
}
Otherwise just use separate TopAppBar
in each screen.
Upvotes: 0