最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

android - Bottom navigation bar not visible on conditional navigation logic - Stack Overflow

programmeradmin3浏览0评论

I'm implementing a bottom navigation bar in Jetpack Compose using NavHostController, but the navigation bar does not appear even though my condition to determine its visibility seems correct.

Here’s my setup:

  1. I have @Serializable objects representing my destinations:
@Serializable
data object ProfileScreen

@Serializable
data object FeatureOne

@Serializable
object HomeScreenNavigation

@Serializable
object RegisterNavigation

@Serializable
object SignInNavigation
  1. My HomeTopLevelNavigation composable initializes a list of top-level destinations and determines if the navigation bar should be visible based on the current destination:
import android.util.Log
import androidxpose.material3.NavigationBar
import androidxpose.material3.NavigationBarItem
import androidxpose.material3.Text
import androidxpose.runtime.Composable
import androidxpose.runtime.getValue
import androidxpose.runtime.mutableStateOf
import androidxpose.runtime.saveable.rememberSaveable
import androidxpose.runtime.setValue
import androidxpose.ui.res.stringResource
import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController
import androidx.navigationpose.currentBackStackEntryAsState
import androidx.navigation.navOptions
import com.hub.travelandroid.home.ui.R
import com.hub.travelandroid.home.ui.model.HomeTopLevelDestination
import com.hub.travelandroid.home.ui.screen.FeatureOne
import com.hub.travelandroid.home.ui.screen.ProfileScreen

@Composable
fun HomeTopLevelNavigation(navController: NavHostController) {
    val homeTopLevelDestinations = listOf(
        HomeTopLevelDestination(
            titleResId = R.string.profile_menu_item,
            route = ProfileScreen.toString()
        ),
        HomeTopLevelDestination(
            titleResId = R.string.profile_menu_item,
            route = FeatureOne.toString(),
        ),
    )
    val navBackStackEntry by navController.currentBackStackEntryAsState()
    val currentDestination = navBackStackEntry?.destination

    var selectedDestinationRoute by rememberSaveable { mutableStateOf(homeTopLevelDestinations[0].route) }

    val isNavigationBarVisible =
        currentDestination?.hierarchy?.any { destination ->
            homeTopLevelDestinations.any { it.route == destination.route }
        } == true

    Log.e("TAG", "HomeTopLevelNavigation: $isNavigationBarVisible")
    Log.e("TAG", "HomeTopLevelNavigation: currentDestination ${currentDestination?.route}")
    Log.e(
        "TAG",
        "HomeTopLevelNavigation: homeTopLevelDestinations ${homeTopLevelDestinations.first().route}"
    )
    if (isNavigationBarVisible)
        HomeNavigationBar(
            homeTopLevelDestinations = homeTopLevelDestinations,
            currentDestinationRoute = currentDestination?.route,
            onNavigate = { destination ->
                navController.navigate(
                    destination.route,
                    navOptions {
                        popUpTo(navController.graph.findStartDestination().id) {
                            saveState = true
                        }
                        launchSingleTop = true
                        restoreState = true
                    }
                )
                selectedDestinationRoute = destination.route
            }
        )
}

@Composable
fun HomeNavigationBar(
    homeTopLevelDestinations: List<HomeTopLevelDestination>,
    currentDestinationRoute: String?,
    onNavigate: (HomeTopLevelDestination) -> Unit
) {
    NavigationBar {
        homeTopLevelDestinations.forEach { destination ->
            NavigationBarItem(
                icon = {},
                label = { Text(stringResource(destination.titleResId)) },
                selected = currentDestinationRoute == destination.route,
                onClick = {
                    onNavigate(destination)
                },
            )
        }
    }
}
  1. My navigation graph looks like this:

@Composable
fun AppNavHost(
    startDestination: Any,
    navHostController: NavHostController = rememberNavController()
) {
    val currentActivity = LocalActivity.current

    Scaffold(
        bottomBar = {
            HomeTopLevelNavigation(navHostController)
        }
    ) {
        NavHost(
            navController = navHostController,
            startDestination = startDestination
        ) {
            registerScreen()
            signInScreen()
            homeScreen(
                onBackPress = {
                    currentActivity?.finish()
                }
            )
        }
    }
}

fun NavGraphBuilder.homeScreen(onBackPress: () -> Unit) {
    navigation<HomeScreenNavigation>(startDestination = ProfileScreen) {
        composable<ProfileScreen> {
            HomeScreenRoute(onBackPress = onBackPress)
        }

        composable<FeatureOne> {
            Text("Feature 1")
        }
    }
}

data class HomeTopLevelDestination(
    @StringRes val titleResId: Int,
    val route: String,
)

Questions:

  1. Am I correctly determining whether to show the navigation bar?
  2. Could toString() on @Serializable objects be causing unexpected behavior in route comparisons?
  3. How can I ensure that the navigation bar is correctly displayed when on top-level destinations?

UPDATE

I tried to use Json.encodeToString() from here but still not working

  val homeTopLevelDestinations = listOf(
        HomeTopLevelDestination(
            titleResId = R.string.profile_menu_item,
            route = Json.encodeToString(ProfileScreen)
        ),
        HomeTopLevelDestination(
            titleResId = R.string.profile_menu_item,
            route = Json.encodeToString(FeatureOne),
        ),
    )

I'm implementing a bottom navigation bar in Jetpack Compose using NavHostController, but the navigation bar does not appear even though my condition to determine its visibility seems correct.

Here’s my setup:

  1. I have @Serializable objects representing my destinations:
@Serializable
data object ProfileScreen

@Serializable
data object FeatureOne

@Serializable
object HomeScreenNavigation

@Serializable
object RegisterNavigation

@Serializable
object SignInNavigation
  1. My HomeTopLevelNavigation composable initializes a list of top-level destinations and determines if the navigation bar should be visible based on the current destination:
import android.util.Log
import androidxpose.material3.NavigationBar
import androidxpose.material3.NavigationBarItem
import androidxpose.material3.Text
import androidxpose.runtime.Composable
import androidxpose.runtime.getValue
import androidxpose.runtime.mutableStateOf
import androidxpose.runtime.saveable.rememberSaveable
import androidxpose.runtime.setValue
import androidxpose.ui.res.stringResource
import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController
import androidx.navigationpose.currentBackStackEntryAsState
import androidx.navigation.navOptions
import com.hub.travelandroid.home.ui.R
import com.hub.travelandroid.home.ui.model.HomeTopLevelDestination
import com.hub.travelandroid.home.ui.screen.FeatureOne
import com.hub.travelandroid.home.ui.screen.ProfileScreen

@Composable
fun HomeTopLevelNavigation(navController: NavHostController) {
    val homeTopLevelDestinations = listOf(
        HomeTopLevelDestination(
            titleResId = R.string.profile_menu_item,
            route = ProfileScreen.toString()
        ),
        HomeTopLevelDestination(
            titleResId = R.string.profile_menu_item,
            route = FeatureOne.toString(),
        ),
    )
    val navBackStackEntry by navController.currentBackStackEntryAsState()
    val currentDestination = navBackStackEntry?.destination

    var selectedDestinationRoute by rememberSaveable { mutableStateOf(homeTopLevelDestinations[0].route) }

    val isNavigationBarVisible =
        currentDestination?.hierarchy?.any { destination ->
            homeTopLevelDestinations.any { it.route == destination.route }
        } == true

    Log.e("TAG", "HomeTopLevelNavigation: $isNavigationBarVisible")
    Log.e("TAG", "HomeTopLevelNavigation: currentDestination ${currentDestination?.route}")
    Log.e(
        "TAG",
        "HomeTopLevelNavigation: homeTopLevelDestinations ${homeTopLevelDestinations.first().route}"
    )
    if (isNavigationBarVisible)
        HomeNavigationBar(
            homeTopLevelDestinations = homeTopLevelDestinations,
            currentDestinationRoute = currentDestination?.route,
            onNavigate = { destination ->
                navController.navigate(
                    destination.route,
                    navOptions {
                        popUpTo(navController.graph.findStartDestination().id) {
                            saveState = true
                        }
                        launchSingleTop = true
                        restoreState = true
                    }
                )
                selectedDestinationRoute = destination.route
            }
        )
}

@Composable
fun HomeNavigationBar(
    homeTopLevelDestinations: List<HomeTopLevelDestination>,
    currentDestinationRoute: String?,
    onNavigate: (HomeTopLevelDestination) -> Unit
) {
    NavigationBar {
        homeTopLevelDestinations.forEach { destination ->
            NavigationBarItem(
                icon = {},
                label = { Text(stringResource(destination.titleResId)) },
                selected = currentDestinationRoute == destination.route,
                onClick = {
                    onNavigate(destination)
                },
            )
        }
    }
}
  1. My navigation graph looks like this:

@Composable
fun AppNavHost(
    startDestination: Any,
    navHostController: NavHostController = rememberNavController()
) {
    val currentActivity = LocalActivity.current

    Scaffold(
        bottomBar = {
            HomeTopLevelNavigation(navHostController)
        }
    ) {
        NavHost(
            navController = navHostController,
            startDestination = startDestination
        ) {
            registerScreen()
            signInScreen()
            homeScreen(
                onBackPress = {
                    currentActivity?.finish()
                }
            )
        }
    }
}

fun NavGraphBuilder.homeScreen(onBackPress: () -> Unit) {
    navigation<HomeScreenNavigation>(startDestination = ProfileScreen) {
        composable<ProfileScreen> {
            HomeScreenRoute(onBackPress = onBackPress)
        }

        composable<FeatureOne> {
            Text("Feature 1")
        }
    }
}

data class HomeTopLevelDestination(
    @StringRes val titleResId: Int,
    val route: String,
)

Questions:

  1. Am I correctly determining whether to show the navigation bar?
  2. Could toString() on @Serializable objects be causing unexpected behavior in route comparisons?
  3. How can I ensure that the navigation bar is correctly displayed when on top-level destinations?

UPDATE

I tried to use Json.encodeToString() from here but still not working

  val homeTopLevelDestinations = listOf(
        HomeTopLevelDestination(
            titleResId = R.string.profile_menu_item,
            route = Json.encodeToString(ProfileScreen)
        ),
        HomeTopLevelDestination(
            titleResId = R.string.profile_menu_item,
            route = Json.encodeToString(FeatureOne),
        ),
    )
Share Improve this question edited yesterday halfer 20.4k19 gold badges109 silver badges202 bronze badges asked Mar 17 at 18:51 Vivek ModiVivek Modi 7,46320 gold badges103 silver badges232 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

Your visibility logic is fine, but using toString() on your @Serializable objects can return unexpected values. Instead, define explicit route strings for your destinations and use those for consistent navigation comparisons.

Also, instead of using toString() you can replace it with decoding/encoding:
https://kotlinlang./docs/serialization.html#serialize-and-deserialize-json

发布评论

评论列表(0)

  1. 暂无评论