如何在NavHost Controller中结合使用Jetpack HorizontalPager与HorizontalPagerIndicator
1. 依赖配置
首先确保项目引入必要依赖:
dependencies { // Compose Navigation implementation("androidx.navigation:navigation-compose:2.7.6") // Jetpack Pager & Material3 Indicator implementation("androidx.compose.foundation:foundation:1.5.4") implementation("androidx.compose.material3:material3:1.1.2") }
2. 定义页面路由与映射逻辑
统一管理9个页面的路由,建立路由与索引的双向映射:
// 9个页面的路由列表 private val pageRoutes = listOf( "page_1", "page_2", "page_3", "page_4", "page_5", "page_6", "page_7", "page_8", "page_9" ) // 根据路由获取对应页面索引 private fun getPageIndex(route: String): Int = pageRoutes.indexOf(route).coerceAtLeast(0) // 根据索引获取对应页面路由 private fun getPageRoute(index: Int): String = pageRoutes.getOrElse(index) { pageRoutes.first() }
3. 创建ViewModel管理导航与Pager状态
用ViewModel同步NavHost导航状态和HorizontalPager的页面索引:
import androidx.lifecycle.ViewModel import androidx.lifecycle.viewmodelScope import androidx.navigation.NavHostController import kotlinx.coroutines.launch import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.setValue class PagerNavViewModel : ViewModel() { var currentPageIndex by mutableStateOf(0) private set // 监听NavHost导航变化,同步到Pager索引 fun syncNavToPager(navController: NavHostController) { viewModelScope.launch { navController.currentBackStackEntryFlow.collect { entry -> entry?.destination?.route?.let { route -> currentPageIndex = getPageIndex(route) } } } } // 当Pager切换页面时,同步到NavHost导航 fun syncPagerToNav(navController: NavHostController, newIndex: Int) { if (newIndex != currentPageIndex) { currentPageIndex = newIndex val targetRoute = getPageRoute(newIndex) if (navController.currentDestination?.route != targetRoute) { navController.navigate(targetRoute) { // 避免重复入栈,保持单实例 popUpTo(navController.graph.startDestinationId) { inclusive = false } launchSingleTop = true } } } } }
4. 主Composable实现联动逻辑
整合HorizontalPager、HorizontalPagerIndicator和NavHost,实现双向同步:
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material3.Scaffold import androidx.compose.material3.HorizontalPager import androidx.compose.material3.HorizontalPagerIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import androidx.compose.foundation.pager.rememberPagerState @Composable fun PagerNavHostScreen() { val viewModel: PagerNavViewModel = viewModel() val navController = rememberNavController() // 初始化Pager状态,页面数量为9 val pagerState = rememberPagerState(pageCount = pageRoutes.size) // 初始化:同步NavHost初始路由到Pager LaunchedEffect(Unit) { viewModel.syncNavToPager(navController) } // Pager页面切换时,同步到NavHost导航 LaunchedEffect(pagerState.currentPage) { viewModel.syncPagerToNav(navController, pagerState.currentPage) } // ViewModel索引变化时,同步到Pager滚动 LaunchedEffect(viewModel.currentPageIndex) { pagerState.animateScrollToPage(viewModel.currentPageIndex) } Scaffold( bottomBar = { // 底部显示页面指示器 HorizontalPagerIndicator( pagerState = pagerState, modifier = Modifier .fillMaxSize() .padding(16.dp), activeColor = MaterialTheme.colorScheme.primary, inactiveColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.3f) ) } ) { paddingValues -> Surface( modifier = Modifier .fillMaxSize() .padding(paddingValues) ) { HorizontalPager( state = pagerState, modifier = Modifier.fillMaxSize() ) { pageIndex -> // 每个Pager页面对应NavHost的一个目的地 NavHost( navController = navController, startDestination = pageRoutes.first() ) { pageRoutes.forEachIndexed { index, route -> composable(route) { // 替换为你的实际页面内容 PageContent(pageNumber = index + 1) } } } } } } } // 示例页面组件,替换成你的业务页面 @Composable fun PageContent(pageNumber: Int) { // 这里编写页面UI逻辑 }
关键注意事项
- 回退栈控制:若需支持返回键,可在
syncPagerToNav的navigate方法中调整popUpTo参数,或监听返回键事件同步更新Pager索引。 - 状态保存:每个页面的状态请用
rememberSaveable或专属ViewModel管理,避免页面切换时状态丢失。 - 性能优化:通过
HorizontalPager的beyondBoundsPageCount参数控制预加载页面数量,减少不必要的资源消耗。
内容的提问来源于stack exchange,提问作者Slava
相关产品推荐
相关产品推荐

