Jetpack Compose + Navigation - 使用 BottomNavBar 的嵌套导航
Jetpack Compose + Navigation - Nested navigation with BottomNavBar
我正在尝试使用 Jetpack Compose + Jetpack Navigation 实现以下屏幕流程:
Navigation concept
实际上,我可以编写两个单例代码:
- SplashScreen --> HomeScreen(没有 BottomNavBar)
- 主屏幕(带底部导航栏)--> 选项卡
我无法对整个问题进行编码。事实上,我对 NavHost 的管理有疑问。在第一种情况下(SplashScreen -> HomeScreen)我需要在高范围调用 NavHost:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyAppTheme {
//init the Navigation Controller for screen navigation
val navController = rememberNavController()
//setup the Navigation Graph
SetupNavGraph(navController)
而在第二种情况下,我需要在 Scaffold
可组合项的 innerPadding
范围内调用它:
fun MainScreen(navController: NavHostController) {
Scaffold(
bottomBar = {
BottomNavBar(navController)
}
) { //innerPadding scope
//setup the Navigation Graph
SetupNavGraph(navController)
}
}
请假设 SetupNavGraph()
函数按预期工作(调用 NavHost
生成导航树)
- 我尝试使用两个
NavHost
但没有成功。
- 如果我在
setContent()
中设置 NavHost
,我可以加载启动画面并移动到空的 BottomNavBar
屏幕。如果我单击 BottomNavElements
,我可以导航到 child 选项卡(在上面的示例中“收藏夹”、“音乐”、“地点”、“新闻”)但是 BottomNavBar
消失
- 我无法在
innerPadding
范围内设置 NavHost
,因为它仅在切换到主屏幕后加载(在上面的示例中“收藏夹选项卡”+ BottomBarNav)
我发现的唯一解决方法是在每个 BottomNav child 选项卡中生成 BottomNavBar
可组合项,但这会产生一个我想避免的可见过渡效果,而且通常不会'这似乎不是一个好习惯。
好的,我找到了解决办法。这是实现预期结果的步骤:
- 创建两个不同的 NavGraph,一个用于 Splash->MainScreen,另一个用于 BottomNavBar
const val ROOT_ROUTE = "root"
@Composable
fun SetupRootNavGraph(navController: NavHostController) {
NavHost(
navController = navController,
startDestination = Screen.FirstScreen.route,
route = ROOT_ROUTE
) {
composable(Screen.FirstScreen.route) { FirstScreen(navController)}
composable(Screen.SecondScreen.route) { MainScreen(navController)}
}
}
const val BOTTOM_BAR_ROUTE = "bottomBar"
@Composable
fun SetupNavGraphBottomBar(navController: NavHostController) {
NavHost(
navController = navController,
startDestination = BottomBarScreen.FirstElement.route,
route = BOTTOM_BAR_ROUTE
) {
composable(BottomBarScreen.FirstElement.route) { FirstElementScreen() }
composable(BottomBarScreen.SecondElement.route) { SecondElementScreen() }
composable(BottomBarScreen.ThirdElement.route) { ThirdElementScreen() }
}
}
- 在
MainActivity
中初始化 NavController
和 setContent()
之后的 RootNavGraph
。这将负责SplashScreen -> MainScreen 导航树。
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyAppTheme {
//init the Navigation Controller for screen navigation
val navController = rememberNavController()
//setup the Root Navigation Graph
SetupRootNavGraph(navController)
}
}
}
}
- Re-init 屏幕中的
NavController
您有 BottomNavBar(示例中的“MainScreen”)并分配给它 innerPadding
中的 BottomNavGraph
范围。
@Composable
fun MainScreen(navController: NavHostController) {
//Re-initialize the NavController to set a new NavGraph
val navControllerBottomBar = rememberNavController()
Scaffold(
bottomBar = {
BottomNavBar(navControllerBottomBar)
}
) {
//setup the Navigation Graph
SetupNavGraphBottomBar(navControllerBottomBar, user)
}
}
这会很有效!当然,您需要按照 Official docs
中的说明来构建 BottomNavBar
以便管理导航
我正在尝试使用 Jetpack Compose + Jetpack Navigation 实现以下屏幕流程:
Navigation concept
实际上,我可以编写两个单例代码:
- SplashScreen --> HomeScreen(没有 BottomNavBar)
- 主屏幕(带底部导航栏)--> 选项卡
我无法对整个问题进行编码。事实上,我对 NavHost 的管理有疑问。在第一种情况下(SplashScreen -> HomeScreen)我需要在高范围调用 NavHost:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyAppTheme {
//init the Navigation Controller for screen navigation
val navController = rememberNavController()
//setup the Navigation Graph
SetupNavGraph(navController)
而在第二种情况下,我需要在 Scaffold
可组合项的 innerPadding
范围内调用它:
fun MainScreen(navController: NavHostController) {
Scaffold(
bottomBar = {
BottomNavBar(navController)
}
) { //innerPadding scope
//setup the Navigation Graph
SetupNavGraph(navController)
}
}
请假设 SetupNavGraph()
函数按预期工作(调用 NavHost
生成导航树)
- 我尝试使用两个
NavHost
但没有成功。 - 如果我在
setContent()
中设置NavHost
,我可以加载启动画面并移动到空的BottomNavBar
屏幕。如果我单击BottomNavElements
,我可以导航到 child 选项卡(在上面的示例中“收藏夹”、“音乐”、“地点”、“新闻”)但是BottomNavBar
消失 - 我无法在
innerPadding
范围内设置NavHost
,因为它仅在切换到主屏幕后加载(在上面的示例中“收藏夹选项卡”+ BottomBarNav)
我发现的唯一解决方法是在每个 BottomNav child 选项卡中生成 BottomNavBar
可组合项,但这会产生一个我想避免的可见过渡效果,而且通常不会'这似乎不是一个好习惯。
好的,我找到了解决办法。这是实现预期结果的步骤:
- 创建两个不同的 NavGraph,一个用于 Splash->MainScreen,另一个用于 BottomNavBar
const val ROOT_ROUTE = "root"
@Composable
fun SetupRootNavGraph(navController: NavHostController) {
NavHost(
navController = navController,
startDestination = Screen.FirstScreen.route,
route = ROOT_ROUTE
) {
composable(Screen.FirstScreen.route) { FirstScreen(navController)}
composable(Screen.SecondScreen.route) { MainScreen(navController)}
}
}
const val BOTTOM_BAR_ROUTE = "bottomBar"
@Composable
fun SetupNavGraphBottomBar(navController: NavHostController) {
NavHost(
navController = navController,
startDestination = BottomBarScreen.FirstElement.route,
route = BOTTOM_BAR_ROUTE
) {
composable(BottomBarScreen.FirstElement.route) { FirstElementScreen() }
composable(BottomBarScreen.SecondElement.route) { SecondElementScreen() }
composable(BottomBarScreen.ThirdElement.route) { ThirdElementScreen() }
}
}
- 在
MainActivity
中初始化NavController
和setContent()
之后的RootNavGraph
。这将负责SplashScreen -> MainScreen 导航树。
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyAppTheme {
//init the Navigation Controller for screen navigation
val navController = rememberNavController()
//setup the Root Navigation Graph
SetupRootNavGraph(navController)
}
}
}
}
- Re-init 屏幕中的
NavController
您有 BottomNavBar(示例中的“MainScreen”)并分配给它innerPadding
中的BottomNavGraph
范围。
@Composable
fun MainScreen(navController: NavHostController) {
//Re-initialize the NavController to set a new NavGraph
val navControllerBottomBar = rememberNavController()
Scaffold(
bottomBar = {
BottomNavBar(navControllerBottomBar)
}
) {
//setup the Navigation Graph
SetupNavGraphBottomBar(navControllerBottomBar, user)
}
}
这会很有效!当然,您需要按照 Official docs
中的说明来构建BottomNavBar
以便管理导航