Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to access navigator in root Navigator's onBackPressed handler? #333

Open
walfud opened this issue Feb 12, 2024 · 3 comments
Open

How to access navigator in root Navigator's onBackPressed handler? #333

walfud opened this issue Feb 12, 2024 · 3 comments

Comments

@walfud
Copy link

walfud commented Feb 12, 2024

I have a very easy case, just accessing navigator instance in onBackPressed handler. Because LocalNavigator.currentOrThrow need in Composable context, I can't use it in that handler. how to do that?

Example:

@Composable
fun App() {
    MaterialTheme {
        Navigator(
            screen = SplashScreen(),
            onBackPressed = { screen ->
               // <<------- I want accessing `navigator` instance here!!!
                return@Navigator true
            }
        ) { navigator ->
        }
    }
}

Thanks~

@walfud
Copy link
Author

walfud commented Feb 12, 2024

I think that it should expose navigator instance as parameter in onBackPressed handler, right?
@DevSrSouza

@DevSrSouza
Copy link
Collaborator

DevSrSouza commented Feb 22, 2024

You can't. This is a common use case, the onBackPressed API currently does not allow this use case.

There is this open PR that fixs some bugs related to nested navigators #273. I plan to get on back on it soon.

Solution I propose for now, that is what I'm currently using it in personal projects is to replicated what Voyager navigators does under the hood.

This snippet was taken from the Voyager implementation here

Navigator(...) { navigator ->
   BackHandler(
            enabled = navigator.canPop || navigator.parent?.canPop ?: false,
            onBack = {
               // DO anything here with the `navigator`
                if (navigator.pop().not()) {
                        navigator.parent?.pop()
                    }
            }
    )

   CurrentScreen()
}

@akardas16
Copy link

You don't need to access navigator instance in Navigator onBackPressed. Here is how I used

 Navigator(LoadingScreen, onBackPressed = { currentScreen ->
                    when (currentScreen.key) {
                        LoadingScreen.key, IntroductionScreen.key, WelcomeScreen.key -> return@Navigator false
                        else -> return@Navigator true
                    }
                }) { navigator -> ...}

In your Screen, use (you can access navigator in screen easily)

BackPressHandler {  //back pressed
          //Do Something
  }
@Composable
fun BackPressHandler(
    backPressedDispatcher: OnBackPressedDispatcher? =
        LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher,
    onBackPressed: () -> Unit
) {
    val currentOnBackPressed by rememberUpdatedState(newValue = onBackPressed)

    val backCallback = remember {
        object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                currentOnBackPressed()
            }
        }
    }

    DisposableEffect(key1 = backPressedDispatcher) {
        backPressedDispatcher?.addCallback(backCallback)

        onDispose {
            backCallback.remove()
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants