You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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的点击回调没有携带当前科目的信息,导致所有项点击都跳转到固定的物理科目页面。按以下步骤修改:

  1. 修改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) // 传入当前点击的科目
            }
        }
    }
}
  1. 修改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)
})
  1. 补充导航配置中缺失的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 05:42:02