Kashinath
Kashinath

Reputation: 370

How to use Jetpack compose app bar backbutton

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

Answers (5)

Mendroid
Mendroid

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

paolo
paolo

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

ThinkDeep
ThinkDeep

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

Naveed
Naveed

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

S Haque
S Haque

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

Related Questions