architecture-components-samples icon indicating copy to clipboard operation
architecture-components-samples copied to clipboard

BottomNavigationView. Navigation to destination with deeplink cause to add destination fragment also in first tab

Open AlexMobileStyles opened this issue 4 years ago • 10 comments
trafficstars

Let's say we have a bottom navigation view with 4 tab, we fave a deeplink for fragment in 4 tab, so when navigate with this deeplink, the 4 tab are selected - it's ok, but when after this manually select firts tab the fragment from 4 tab are added also in first tab.

AlexMobileStyles avatar Jun 17 '21 06:06 AlexMobileStyles

Problem solved my self with this solution i added an custom extenstion for bottom nav view

fun BottomNavigationView.setupWithNavController(navController: NavController?) {
    navController?.let {
        this.setupWithNavController(it)
    }
    this.setOnItemSelectedListener { menuItem ->
        val builder = NavOptions.Builder().setLaunchSingleTop(true).setRestoreState(false)
        val graph = navController?.currentDestination?.parent
        val destination = graph?.findNode(menuItem.itemId)
        if (menuItem.order and Menu.CATEGORY_SECONDARY == 0) {
            navController?.graph?.findStartDestination()?.id?.let {
                builder.setPopUpTo(
                    it,
                    inclusive = false,
                    saveState = true
                )
            }
        }
        val options = builder.build()
        destination?.id?.let { id -> navController.navigate(id, null, options) }
        return@setOnItemSelectedListener true
    }
}

problem was in setRestoreState(true)

AlexMobileStyles avatar Jun 17 '21 09:06 AlexMobileStyles

Please open a ticket here, otherwise they will not fix it, Google Issue Tracker

catluc avatar Jul 02 '21 08:07 catluc

Hello, I used navigation components version 2.4.0-alpha04 and I have same issue, my solution is inspired by @AlexMobileStyles, the main problem is with setPopUpTomethod with saveState = true, btw is issue already reported on Google Issue Tracker?

fun BottomNavigationView.setupWithNavControllerFixed(navController: NavController?) {
    navController?.let {
        this.setupWithNavController(it)
    }

    NavigationUI

    /**
     *  Fixed by 
     *     NavOptions setRestoreState(false) with  setPopUpTo(saveState = true)
     *     or
     *     NavOptions setRestoreState(true) with  setPopUpTo(saveState = false)
     *  
     *  @see [NavigationUI.onNavDestinationSelected]
     */
    this.setOnItemSelectedListener {item->

        val builder = NavOptions.Builder().setLaunchSingleTop(true).setRestoreState(true)
        if (
            navController!!.currentDestination!!.parent!!.findNode(item.itemId)
                    is ActivityNavigator.Destination
        ) {
            builder.setEnterAnim(R.anim.nav_default_enter_anim)
                .setExitAnim(R.anim.nav_default_exit_anim)
                .setPopEnterAnim(R.anim.nav_default_pop_enter_anim)
                .setPopExitAnim(R.anim.nav_default_pop_exit_anim)
        } else {
            builder.setEnterAnim(R.animator.nav_default_enter_anim)
                .setExitAnim(R.animator.nav_default_exit_anim)
                .setPopEnterAnim(R.animator.nav_default_pop_enter_anim)
                .setPopExitAnim(R.animator.nav_default_pop_exit_anim)
        }
        if (item.order and Menu.CATEGORY_SECONDARY == 0) {
            builder.setPopUpTo(
                navController.graph.findStartDestination().id,
                inclusive = false,
                saveState = false
            )
        }
        val options = builder.build()
        return@setOnItemSelectedListener  try {
            // TODO provide proper API instead of using Exceptions as Control-Flow.
            navController.navigate(item.itemId, null, options)
            true
        } catch (e: IllegalArgumentException) {
            false
        }
    }
}

KamikX avatar Jul 16 '21 06:07 KamikX

But this solution breaks multiple stack saved states and whenever we select any bottom nav item, start destination opens instead of last fragment that was there (state is not saved) Any other solution? @KamikX @AlexMobileStyles

kartik0198 avatar Jan 16 '22 14:01 kartik0198

I think the situation is significantly worse: the Multiple back stacks is completely broken.

example 1: if I am in a second level of the first tab and I deeplink on tab 2, the first tab stops responding

example 2: if I am in a second level of the first tab, I navigate with a deeplink on tab 2, then click on tab 3 and then click on tab 1, tab 2 is displayed

and much more, all just using AdvancedNavigationSample and navigation component 2.4.0

deeplink created using this code inside About fragment class

view.findViewById<Button>(R.id.deepLink).setOnClickListener {
    findNavController().navigate("http://www.example.com/user/Person 2".toUri())
}

xanscale avatar Jan 31 '22 18:01 xanscale

Look's like i've found solution I have two fragments (FragmentA and FragmentB) inside BottomNavigationView I use this code for navigating to FragmentB inside FragmentA

                val navOptions: NavOptions = navBuilder
                    .setPopUpTo(
                        R.id.fragmentA,
                        inclusive = false,
                        saveState = true
                    ).build()

                findNavController().navigate("deeplink://to_fragment_b".toUri(), navOptions)

Backstack working, state saving I used version 2.4.2

Lime94 avatar Apr 17 '22 12:04 Lime94

Oh no sorry it isn't working correct(( After changing item, back stack isn't saving((

Lime94 avatar Apr 19 '22 14:04 Lime94

The issue is in the google issue tracker https://issuetracker.google.com/issues/213131384

sergpetrov avatar Jul 20 '22 12:07 sergpetrov

@Lime94 try using setRestoreState in your navOptions too

        navOptionsBuilder.setRestoreState(true)
        navController?.graph?.findStartDestination()?.id?.let {
            navOptionsBuilder.setPopUpTo(
                it,
                popUpToInclusive,
                saveState = true
            )
        }

NVM - this still wont fix the backstack if you navigate using deeplinks from a non top-level destination

dazza5000 avatar Jan 20 '23 02:01 dazza5000

The solution is here: https://stackoverflow.com/a/78075344/16041661

user98392 avatar Mar 18 '24 10:03 user98392