如何使用 JetPack Compose 在 LazyColumn 项目中单击导航到详细视图?
Posted
技术标签:
【中文标题】如何使用 JetPack Compose 在 LazyColumn 项目中单击导航到详细视图?【英文标题】:How to navigate to Detail View clicking in LazyColumn item with JetPack Compose? 【发布时间】:2021-11-09 21:16:22 【问题描述】:我正在尝试使用 JetPack Compose 创建一个应用程序(第一次),但我遇到了一些导航问题。该应用程序有一个底部栏,其中包含 3 个导航到所选屏幕的项目。
这可行,问题是当我尝试访问其中一个屏幕中的 LazyColumn 的一项时。我想导航到显示所选项目数据的另一个屏幕(配置文件),但我找不到方法。无论我如何尝试,我总是得到这样的“@Composable 调用只能在 @Composable 函数的上下文中发生”。
有人能帮我解释一下怎么做吗?我想要的是了解如何以及为什么,而不仅仅是复制。
谢谢
MainActivity
class MainActivity : ComponentActivity()
@ExperimentalFoundationApi
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContent
val systemUiController = rememberSystemUiController()
SideEffect
systemUiController.setStatusBarColor(color = PrimaryDark)
AppTheme()
MainScreen()
@ExperimentalFoundationApi
@Composable
fun MainScreen()
val navController = rememberNavController()
val navigationItems = listOf(Obras, Talleres, Ajustes)
Scaffold(bottomBar =
BottomNavigationBar(
navController = navController,
items = navigationItems
)
)
NavigationHost(navController)
NavigationHost.kt
@ExperimentalFoundationApi
@Composable
fun NavigationHost(navController: NavHostController)
NavHost(navController = navController, startDestination = Obras.route)
composable(Obras.route)
Pantalla1(navigateToProfile = authorId ->
navController.navigate("$Profile.route/$authorId")
)
composable(Talleres.route)
Pantalla2()
composable(Ajustes.route)
Pantalla3()
composable(
Profile.route + "/authorId",
arguments = listOf(navArgument("authorId") type = NavType.StringType )
) backStackEntry ->
val authorId = backStackEntry.arguments!!.getString("authorId")!!
Profile(authorId)
Pantalla1.kt
typealias AuthorId = String
@ExperimentalCoroutinesApi
@Composable
fun Pantalla1(navigateToProfile: (AuthorId) -> Unit)
Column(
modifier = Modifier
.fillMaxSize()
.padding(
paddingValues = PaddingValues(
bottom = 50.dp
)
),
)
AutoresInfo(navigateToProfile)
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun AutoresInfo(navigateToProfile: (AuthorId) -> Unit)
var autoresList by remember
mutableStateOf<List<Autor>?>(null)
JetFirestore(path = collection("autores") ,
queryOnCollection = orderBy("nombre", Query.Direction.ASCENDING) ,
onRealtimeCollectionFetch = value, exception ->
autoresList = value.getListOfObjects()
)
autoresList?.let
val grouped = it.groupBy it.nombre[0]
LazyColumn(
modifier = Modifier.fillMaxSize()
)
grouped.forEach (initial, autoresForInitial) ->
stickyHeader
StickyHeaderAutores(initial = initial.toString())
items(autoresForInitial, key = autor -> autor.nombre ) autor ->
Surface(modifier = Modifier.clickable navigateToProfile(autor.nombre) )
@OptIn(coil.annotation.ExperimentalCoilApi::class)
AutorCard(autor)
?: Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
)
CircularProgressIndicator(
color = Color.Red,
modifier = Modifier
.size(50.dp)
)
【问题讨论】:
导航到个人资料屏幕的导航代码在哪里? 【参考方案1】:第 1 步。为您的个人资料导航路线添加参数。查看 documentation 关于使用参数导航
composable(
Profile.route + "/authorId",
arguments = listOf(navArgument("authorId") type = NavType.StringType )
) backStackEntry ->
val authorId = backStackEntry.arguments!!.getString("authorId")!!
Profile(authorId)
第 2 步。您需要从 NavigationHost
传递 navigateToProfile
函数。如果不是String
,您可以将AuthorId
替换为Int
(或其他类型):
typealias AuthorId = String
@Composable
fun NavigationHost(navController: NavHostController)
NavHost(navController = navController, startDestination = Obras.route)
composable(Obras.route)
Pantalla1(navigateToProfile = authorId ->
navController.navigate("$Profile.route/$authorId")
)
...
@Composable
fun Pantalla1(navigateToProfile: (AuthorId) -> Unit)
...
AutoresInfo(navigateToProfile)
...
@Composable
fun AutoresInfo(navigateToProfile: (AuthorId) -> Unit)
...
items(autoresForInitial, key = autor -> autor.nombre ) autor ->
Surface(modifier = Modifier.clickable
navigateToProfile(author.id)
)
AutorCard(autor)
...
第 3 步。在您的可组合配置文件中,您需要按 id 获取作者。不确定JetFirestore
是什么,您可能应该使用它。
@Composable
fun Profile(id: AuthorId)
JetFirestore(
// fetch author by id
)
【讨论】:
谢谢,我正在尝试这个,但没有用。我不知道为什么,但是当我单击一个项目时,它什么也不做。我更新了代码。 @Komito添加日志,检查clickable
是否被调用,然后检查navController.navigate
是否在NavigationHost
内部被调用
我发现了问题。在 AutorCard 我有一个空的可点击。我删除了它,所以现在它可以正常工作了。非常感谢您的帮助。【参考方案2】:
创建一个包含如下路由的密封类
sealed class Screen(val route:String)
object MyListScreen:Screen("my_list_screen")
object MyDetailScreen:Screen("my_detail_screen")
使用 Row 创建 listItem 以接收列表和点击事件,如下所示
@Composable
fun MyListItem(
yourList: YourList,
onItemClick:(yourList) -> Unit
)
Row(
modifier = Modifier
.fillMaxWidth()
.clickable
onItemClick(yourList)
)
//something here
在 LazyColoumn 的 listScreen 中,您可以执行此操作
LazyColumn(modifier = Modifier.fillMaxSize())
items (state.yourfreshlist)mylist->
MyListItem(mylist = mylist, onItemClick =
navController.navigate(Screen.MyDetailScreen.route+"/$mylist.something")
)
你的宿主会是这样的
NavHost(
navController = navController,
startDestination = Screen.MyListScreen.route
)
composable(
route = Screen.MyListScreen.route
)
MyListScreen(navController)
composable(
route = Screen.MyDetailScreen.route + "/anything here id for example"
)
MyDetailScreen()
更多信息可以浏览docs
【讨论】:
以上是关于如何使用 JetPack Compose 在 LazyColumn 项目中单击导航到详细视图?的主要内容,如果未能解决你的问题,请参考以下文章
Jetpack Compose ScrollableTabRow 如何调整最小宽度
如何将 CameraView 与 Jetpack Compose 一起使用?
如何在 jetpack compose 中使用 MotionLayout、MotionScene、ConstraintSet?