Reputation: 370
getActionBar().setDisplayHomeAsUpEnabled(true) this i was using for normal android AppCompatActivity to switch between two or more activity.can any one tell me how to do this in jetpack Compose ?
Upvotes: 24
Views: 36383
Reputation: 61
Easiest way by my opinion is with BackHandler Composable. I use it in my little apps where everything composes in one Activity. You don't even need NavHost. For Example:
@Composable
fun Screen2 (
modifier: Modifier = Modifier,
goHomeScreen: () -> Unit
)
{
val noteViewModel: NoteViewModel = viewModel()
NoteOpen (noteViewModel = noteViewModel, modifier = modifier, goHomeScreen = goHomeScreen)
BackHandler (
onBack = { goHomeScreen() },
enabled = true
)
}
//In MainActivity.kt for example:
@Composable
fun MemoMain(
...,
modifier: Modifier = Modifier,
memoViewModel: MemoViewModel = viewModel()
) {
var activeNoteIndex by rememberSaveable { mutableIntStateOf(-1) }
if (activeNoteIndex == 0) {
Screen2(
modifier = modifier,
dbDao = memoViewModel.noteDao,
goHomeScreen = { activeNoteIndex = -1 },
activeNote = activeNote
)
} else {
MemoApp(
modifier = modifier,
memoViewModel = memoViewModel,
noteList = homeUiState.noteList,
goScreen2 = { activeNoteIndex = it }
)
}
}
Upvotes: 1
Reputation: 420
Here a full Example of using compose app bar back button. https://github.com/pgatti86/toolbar-demo
val navController: NavHostController = rememberNavController()
val isBackButtonVisible by remember {
derivedStateOf {
navController.previousBackStackEntry != null
}
}
use derived state to show or hide your back button icon
Upvotes: 6
Reputation: 697
Both other solutions are fine and helped me refine my own variation that I have to extract because of usage on many screens.
@Composable
fun MyScaffold(@StringRes titleId: Int, upAvailable: Boolean, onUpClicked: () -> Unit, content: @Composable (PaddingValues) -> Unit) {
Scaffold(
topBar = {
TopAppBar(title = { MyText(textId = titleId) }, backgroundColor = Color.Black, navigationIcon = {
if (upAvailable) {
IconButton(onClick = { onUpClicked() }) {
Icon(imageVector = Icons.Filled.ArrowBack, contentDescription = "Back", tint = Color.White)
}
}
})
},
backgroundColor = Color.Transparent,
content = content
)
}
Where MyText is just my variant that accepts string res and has white text color.
Usage:
val isUpAvailable by viewModel.upAvailable.collectAsState()
MyScaffold(titleId = R.string.title, upAvailable = isUpAvailable, onUpClicked = { viewModel.navigateUp() }) {
// Content
}
Then my BaseViewModel provides upAvailable and navigateUp() via navigationManager dependency which handles navigation via navigationController:
if (destination.route == NAVIGATE_UP) { navController.navigateUp() }
...
// set on every navigation
navigationManager.setUpAvailable(navController.previousBackStackEntry != null)
Upvotes: 5
Reputation: 3202
The other answer is correct for showing the back button. This is a slight alternative that uses TopAppBar
composable instead.
I also ran into a similar issue. The main thing I wanted to solve was hiding the back button when you are at the root or if there is nothing left in backstack, since setDisplayHomeAsUpEnabled
took care of that as long as you specified your parent.
Assuming you are using the nav controller with compose, you can do something like this
val navController = rememberNavController()
Scaffold(
topBar = {
TopAppBar(
title = { Text(text = "app bar title") },
navigationIcon = if (navController.previousBackStackEntry != null) {
{
IconButton(onClick = { navController.navigateUp() }) {
Icon(
imageVector = Icons.Filled.ArrowBack,
contentDescription = "Back"
)
}
}
} else {
null
}
)
},
content = {
// Body content
}
)
The key here is to set navigationIcon
argument of TopAppBar
to null
when there is nothing in the back stack. This way the back arrow will be hidden when you are at the root and shown otherwise.
Upvotes: 36
Reputation: 7271
You can wrap your main content inside an Scaffold
composable and use the topBar
to add the back button and handle back action like this:
import androidx.compose.material.Scaffold
.
.
Scaffold(
topBar = {
Row {
Icon(
imageVector = Icons.Filled.ArrowBack,
contentDescription = "Back",
modifier = Modifier
.padding(16.dp)
.clickable {
// Implement back action here
}
)
}
}
) {
BodyContent()
}
Upvotes: 3