如何在Jetpack Compose中实现LazyVerticalGrid点击跳转对应科目页面
问题描述
我想实现从首页跳转至对应科目页面,点击每个科目时,新页面加载对应科目的数据。但目前点击LazyVerticalGrid中的任意项,都会跳转到同一个科目页面。
首页[科目板块]代码
@Composable fun SubjectSection(onClick: () -> Unit, modifier: Modifier = Modifier) { Text( text = "Subjects", style = MaterialTheme.typography.titleMedium ) Spacer(modifier = Modifier.height(8.dp)) LazyVerticalGrid( columns = GridCells.Fixed(2), //contentPadding = PaddingValues(8.dp) ) { items(subjectList, key = { it.id }) { subject -> SubjectBox(subject = subject) { onClick() } } } } @Composable fun SubjectBox(subject: Subject, onClick: () -> Unit) { Box( modifier = Modifier .padding(end = 8.dp, bottom = 8.dp) .background(subject.color, RoundedCornerShape(8.dp)) .width(140.dp) .height(40.dp) .clickable { onClick() } ) { TextButton( onClick = onClick, modifier = Modifier.align(Alignment.CenterStart) ) { Text( text = subject.name, style = MaterialTheme.typography.bodyMedium, modifier = Modifier //.padding(start = 5.dp) //.align(Alignment.CenterStart) ) } Image( painter = painterResource(id = subject.image), contentDescription = null, modifier = Modifier .size(60.dp) .padding(end = 5.dp) .align(Alignment.CenterEnd) ) } }
函数调用代码
SubjectSection(onClick = { navController.navigate(Screen.SubjectPhysics.route) })
科目页面代码
@Composable fun SubjectScreen( subjects: Subjects, categories: List<ChapterCategory>, modifier: Modifier = Modifier ) { Column { Box( modifier = modifier .wrapContentSize(align = TopCenter) .background(color = Color(0xFFF9E9FE)) ) { Column { HeaderSection { } SubjectNameBox(subjects) } } Box(modifier = modifier.fillMaxSize()) { ChapterColumn(categories = categories) } } } @Composable fun HeaderSection( modifier: Modifier = Modifier, onBack: () -> Unit ) { Row( modifier = modifier .fillMaxWidth() .padding(start = 0.dp, end = 20.dp, top = 20.dp, bottom = 20.dp), horizontalArrangement = Arrangement.SpaceBetween ) { IconButton(onClick = onBack) { Icon(imageVector = Icons.Default.ArrowBack, contentDescription = null) } Icon( imageVector = Icons.Default.Search, contentDescription = null, modifier = Modifier.align(CenterVertically) ) } } @Composable fun SubjectNameBox(subjects: Subjects, modifier: Modifier = Modifier) { Row( modifier = Modifier .fillMaxWidth() .padding(20.dp), horizontalArrangement = Arrangement.SpaceBetween ) { Text( text = subjects.name, style = MaterialTheme.typography.headlineLarge ) Image( painter = painterResource(id = subjects.iconResId), contentDescription = null, modifier = Modifier.size(80.dp) ) } } @Composable fun ChapterBox( modifier: Modifier = Modifier, chapterName: ChapterName ) { Box( modifier = modifier .fillMaxSize() .padding(2.dp) .background(color = Color(0xFF8F6F5FA), RoundedCornerShape(8.dp)) ) { Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(16.dp), modifier = Modifier .fillMaxWidth() .padding(16.dp) ) { Image(painter = painterResource(id = chapterName.icon), contentDescription = null) Column { Text(text = chapterName.name, maxLines = 1, overflow = TextOverflow.Ellipsis) Spacer(Modifier.height(4.dp)) Text( text = chapterName.description, style = MaterialTheme.typography.bodyMedium, maxLines = 1, overflow = TextOverflow.Ellipsis ) } } } } @OptIn(ExperimentalFoundationApi::class) @Composable fun ChapterColumn( categories: List<ChapterCategory>, modifier: Modifier = Modifier ) { LazyColumn() { categories.forEach { category -> stickyHeader { ChapterHeader(category.name) } items(category.chapters) { chapter -> ChapterBox(chapterName = chapter) } } } } @Composable fun ChapterHeader( category: String, modifier: Modifier = Modifier ) { Text( text = category, fontSize = 16.sp, fontWeight = FontWeight.Bold, modifier = modifier .fillMaxWidth() .background(MaterialTheme.colorScheme.primaryContainer) .padding(16.dp) ) }
Subjects密封类代码
sealed class Subjects(val name: String, val iconResId: Int, val chapters: List<ChapterName>) object Chemistry : Subjects(" Chemistry", R.drawable.chemistry, chapterNameChemistryOrganic) object Biology : Subjects(" Biology", R.drawable.biology, chapterNameChemistryOrganic) object Physics : Subjects(" Physics", R.drawable.physics3, chapterNameChemistryOrganic) object Mat : Subjects("MAT", R.drawable.maths1, chapterNameMat) object MockTest : Subjects("Mock Test", R.drawable.maths1, chapterNameMockTest)
Chapter Category数据类代码
data class ChapterCategory( val name: String, val chapters: List<ChapterName> ) val allChaptersChemistry = listOf( ChapterCategory("Physical Chemistry", chapterNameChemistryPhysical), ChapterCategory("Organic Chemistry", chapterNameChemistryOrganic), ChapterCategory("Inorganic Chemistry", chapterNameChemistryInorganic), ) val allChaptersBiology = listOf( ChapterCategory(name = "Zoology", chapters = chapterNameBiologyZoology), ChapterCategory(name = "Botany", chapters = chapterNameBiologyBotany) ) val allChaptersPhysics = listOf( ChapterCategory(name = "Mechanics", chapters = chapterNamePhysicsMechanics), ChapterCategory(name = "Thermodynamics", chapters = chapterNamePhysicsThermodynamics), ChapterCategory(name = "Sound", chapters = chapterNamePhysicsSound), ChapterCategory(name = "Optics", chapters = chapterNamePhysicsOptics), ChapterCategory(name = "Electrostatics", chapters = chapterNamePhysicsElectrostatics), ChapterCategory( name = "Electricity And Magnetism", chapters = chapterNamePhysicsElectricityAndMagnetism ), ChapterCategory(name = "Modern Physics", chapters = chapterNamePhysicsModernPhysics), )
导航配置代码
@Composable fun NavigationScreen() { val navController = rememberNavController() NavHost( navController = navController, startDestination = Screen.Navigation.route ) { composable(route = Screen.Home.route) { HomeScreen(navController) } composable(route = Screen.Navigation.route) { BottomNavigationScreen(navController) } composable(route = Screen.SubjectPhysics.route) { SubjectScreen(subjects = Physics, categories = allChaptersPhysics) } composable(route = Screen.SubjectChemistry.route) { SubjectScreen(subjects = Chemistry, categories = allChaptersChemistry) } composable(route = Screen.SubjectBiology.route) { SubjectScreen(subjects = Biology, categories = allChaptersBiology) } } }
解决方案
问题根源是SubjectSection的点击回调没有携带当前科目的信息,导致所有项点击都跳转到固定的物理科目页面。按以下步骤修改:
- 修改
SubjectSection的点击回调,让它接收Subject参数:
@Composable fun SubjectSection(onClick: (Subject) -> Unit, modifier: Modifier = Modifier) { Text( text = "Subjects", style = MaterialTheme.typography.titleMedium ) Spacer(modifier = Modifier.height(8.dp)) LazyVerticalGrid(columns = GridCells.Fixed(2)) { items(subjectList, key = { it.id }) { subject -> SubjectBox(subject = subject) { onClick(subject) // 传入当前点击的科目 } } } }
- 修改
SubjectSection的调用,根据点击的科目匹配对应的导航路由:
SubjectSection(onClick = { subject -> val route = when(subject) { is Physics -> Screen.SubjectPhysics.route is Chemistry -> Screen.SubjectChemistry.route is Biology -> Screen.SubjectBiology.route is Mat -> Screen.SubjectMat.route // 需提前在Screen中定义该路由 is MockTest -> Screen.SubjectMockTest.route // 需提前在Screen中定义该路由 else -> Screen.Home.route } navController.navigate(route) })
- 补充导航配置中缺失的MAT和MockTest页面(如果需要):
composable(route = Screen.SubjectMat.route) { SubjectScreen(subjects = Mat, categories = allChaptersMat) // 需定义对应的章节数据allChaptersMat } composable(route = Screen.SubjectMockTest.route) { SubjectScreen(subjects = MockTest, categories = allChaptersMockTest) // 需定义对应的章节数据allChaptersMockTest }
修改完成后,点击不同科目即可跳转到对应的页面,加载对应科目的数据。
内容的提问来源于stack exchange,提问作者Hari Joshi
相关产品推荐
相关产品推荐

