vt600c
vt600c

Reputation: 191

Does Android Jetpack Navigation Kotlin DSL support bottom navigation with multiple stack?

I am using latest Jetpack Navigation with native support of multiple stack for bottom navigation: https://medium.com/androiddevelopers/navigation-multiple-back-stacks-6c67ba41952f and it works fine. The only limitation for me that I have to define all navigation in navigation.xml and cannot change it during the runtime.

Apparently I found out that there is an Kotlin DSL for building navigation graph programmatically: https://developer.android.com/guide/navigation/navigation-kotlin-dsl

Unfortunately I cannot find any examples of using this Kotlin DSL for bottom navigation with multiple stack.

Upvotes: 3

Views: 355

Answers (1)

Vladyslav Klymiuk
Vladyslav Klymiuk

Reputation: 1

Don't forget to specify tittle = DestinationName in your menu. Title must be equal to your Destination class name

data class TopLevelRoute<T : Destination>(val route: T)

val topLevelRoutes = listOf(
    TopLevelRoute(Destination.Home),
    TopLevelRoute(Destination.Warehouse),
    TopLevelRoute(Destination.Profile),
)

sealed class Destination {

    @Serializable
    data object Home : Destination()

    @Serializable
    data object Warehouse : Destination()

    @Serializable
    data class ProductDetail(val id: Int) : Destination()

    @Serializable
    data class ProductManage(val id: Int? = null) : Destination()

    @Serializable
    data object Profile : Destination()

    companion object {
        inline fun <reified T: Destination> from(savedStateHandle: SavedStateHandle): T = savedStateHandle.toRoute<T>()
    }
}

fun NavigationBarView.setupWithNavController(
    navController: NavController,
    fragmentContainer: FragmentContainerView
) {
    navController.addOnDestinationChangedListener { _, destination, _ ->
        when {
            destination.hasRoute(Destination.ProductDetail::class) -> {
                hideNavigationBarWithAnimation(this, fragmentContainer)
            }

            else -> {
                showNavigationBarWithAnimation(this, fragmentContainer)
            }
        }

        val matchingRoute = topLevelRoutes.find { destination.hasRoute(it.route::class) }

        if (matchingRoute != null) {
            menu.findItemByTitle(matchingRoute.route::class.simpleName)?.isChecked = true
        }
    }

    setOnItemSelectedListener { item ->
        val selectedRoute = topLevelRoutes.find { it.route::class.simpleName == item.title }

        if (selectedRoute != null) {
            val isSelected =
                navController.currentDestination?.hasRoute(selectedRoute.route::class) == true

            if (!isSelected) {
                navController.navigate(selectedRoute.route) {
                    popUpTo(navController.graph.startDestinationId) {
                        saveState = true
                    }
                    launchSingleTop = true
                    restoreState = true
                }
            }
            return@setOnItemSelectedListener true
        }
        false
    }
}

private fun Menu.findItemByTitle(title: String?): MenuItem? {
    for (i in 0 until size()) {
        val item = getItem(i)
        if (item.title == title) {
            return item
        }
    }
    return null
}

Upvotes: 0

Related Questions