提问人:Dolev Dublon 提问时间:12/3/2022 最后编辑:z.g.yDolev Dublon 更新时间:2/16/2023 访问量:5522
如何将一个可组合项作为其参数传递给另一个可组合项,并在 Jetpack Compose 中显示/运行它
How to pass a Composable to another Composable as its parameter and display/run it in Jetpack Compose
问:
我有这个抽屉,我在 youtube 上学会了制作
https://www.youtube.com/watch?v=JLICaBEiJS0&list=PLQkwcJG4YTCSpJ2NLhDTHhi6XBNfk9WiC&index=31菲利普·拉克纳
我想将抽屉添加到我的应用程序中,该应用程序具有多个屏幕,其中一些不需要抽屉,因此我实现了带有屏幕的导航,并且某些屏幕还需要将抽屉包裹在它们顶部。
这是抽屉的代码
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
drawerGesturesEnabled = scaffoldState.drawerState.isOpen,
scaffoldState = scaffoldState, topBar = {
AppBar(onNavigationIconClick = {
scope.launch {
scaffoldState.drawerState.open()
}
})
}, drawerContent = {
DrawerHeader()
DrawerBody(items = listOf(
MenuItem(
id = "home",
title = "Home",
contentDescription = "Go to home screen",
icon = Icons.Default.Home
),
MenuItem(
id = "settings",
title = "Settings",
contentDescription = "Go to Settings screen",
icon = Icons.Default.Settings
),
MenuItem(
id = "help",
title = "Help",
contentDescription = "Go to help screen",
icon = Icons.Default.Info
),
), onItemClick = {
println("Clicked on ${it.title}")
when (it.id) {
"home" -> {
println("Clicked on ${it.title}")
}
"settings" -> {
println("Clicked on ${it.title}")
}
"help" -> {
println("Clicked on ${it.title}")
}
}
})
}) {
Text(text = "Hello World")
}
文本 = Hellow 世界是我想传递屏幕参数的地方,我不知道该怎么做。我想添加一个参数,该参数采用可组合函数并在其中运行它
我按照这个关于如何在 kotlin 中导航的导航视频进行了操作
https://www.youtube.com/watch?v=4gUeyNkGE3g&list=PLQkwcJG4YTCSpJ2NLhDTHhi6XBNfk9WiC&index=18
它有 3 个大文件,所以如果你问我,我会把它们发布在这里,但我会尽量更具体地说明需要什么
composable(route = Screen.RegisterScreen.route) {
RegisterScreen(navController = navCotroller)
}
如果我把代码放在抽屉里,它工作得很好,但我想拆分代码以更干净,因为我在更多地方使用抽屉
代码的工作方式如下
composable(route = Screen.PreferenceScreen.route) {
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
drawerGesturesEnabled = scaffoldState.drawerState.isOpen,
scaffoldState = scaffoldState,
topBar = {
AppBar(onNavigationIconClick = {
scope.launch {
scaffoldState.drawerState.open()
}
})
},
drawerContent = {
DrawerHeader()
DrawerBody(items = listOf(
MenuItem(
id = "swipe",
title = "Swipe",
contentDescription = "Go to Swipe screen",
icon = Icons.Default.Home
),
MenuItem(
id = "settings",
title = "Settings",
contentDescription = "Go to Settings screen",
icon = Icons.Default.Settings
),
MenuItem(
id = "profile",
title = "Profile",
contentDescription = "Go to profile screen",
icon = Icons.Default.Info
),
), onItemClick = {
when (it.id) {
"swipe" -> {
navCotroller.navigate(Screen.SwipeScreen.route)
}
"settings" -> {
navCotroller.navigate(Screen.PreferenceScreen.route)
}
"profile" -> {
navCotroller.navigate(Screen.CelebProfileScreen.route)
}
}
})
}) {
-----> PreferenceScreen(navController = navCotroller)
}
}
但这不是干净的代码!!我怎样才能使用函数指针来使它工作?
答:
我无法编译您的代码,我不确定这是否会解决您的问题,但基于此
...我想添加一个参数,该参数采用可组合函数并运行 它里面
您可以将其用作参考。考虑这个可组合项,它接受任何可组合项并在其中运行它
@Composable
fun AnyComposable(
anyComposable: @Composable () -> Unit
) {
anyComposable()
}
另一个可组合项使用上面的可组合项,并将任何其他可组合项传递给它,如下所示
@Composable
fun MyScreen() {
// big red Box composable
val composable1 = @Composable {
Box (
modifier = Modifier
.size(200.dp)
.background(Color.Red)
)
}
// small blue Box composable
val composable2 = @Composable {
Box(
modifier = Modifier
.size(80.dp)
.background(Color.Blue)
)
}
// small green rectangular Box composable
val composable3 = @Composable {
Box(
modifier = Modifier
.size(width = 100.dp, height = 30.dp)
.background(Color.Green)
)
}
var dynamicComposable by remember { mutableStateOf<@Composable () -> Unit> (@Composable { composable1() }) }
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Button(onClick = {
dynamicComposable = composable1
}) {
Text("Comp 1")
}
Button(onClick = {
dynamicComposable = composable2
}) {
Text("Comp 2")
}
Button(onClick = {
dynamicComposable = composable3
}) {
Text("Comp 3")
}
}
AnyComposable {
dynamicComposable()
}
}
}
和输出:
评论
或者,如果接收的可组合项有,比如说一个 ,并且你想事先设置参数可组合项,你可以考虑这个。Column
Alignment
接受任何可组合项的同一可组合接收器,但预期的布局是 。Column
@Composable
fun AnyComposable(
anyComposable: @Composable () -> Unit
) {
Column(
modifier = Modifier.fillMaxSize()
) {
anyComposable()
}
}
@Composable
fun MyScreen() {
// big red box at Start of Column
val composable1 : @Composable ColumnScope.() -> Unit = @Composable {
Box (
modifier = Modifier
.align(Alignment.Start)
.size(200.dp)
.background(Color.Red)
)
}
// small blue box at Center of Column
val composable2 : @Composable ColumnScope.() -> Unit = @Composable {
Box(
modifier = Modifier
.align(Alignment.CenterHorizontally)
.size(80.dp)
.background(Color.Blue)
)
}
// small green rectangle at end of column
val composable3 : @Composable ColumnScope.() -> Unit = @Composable {
Box(
modifier = Modifier
.align(Alignment.End)
.size(width = 100.dp, height = 30.dp)
.background(Color.Green)
)
}
var dynamicComposable by remember { mutableStateOf<@Composable ColumnScope.() -> Unit> (@Composable { composable1() }) }
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Button(onClick = {
dynamicComposable = composable1
}) {
Text("Comp 1")
}
Button(onClick = {
dynamicComposable = composable2
}) {
Text("Comp 2")
}
Button(onClick = {
dynamicComposable = composable3
}) {
Text("Comp 3")
}
}
AnyComposable {
dynamicComposable()
}
}
}
输出:
评论
GIF Maker
Choose File and Upload
Size
320-Auto
Convert to GIF
Diskette
Bit Rate (Mbps): 4
Resolution (% of native): 50
嘿,伙计们,如果你想知道我是如何解决我自己的应用程序中的问题,请参阅此代码
最终结果
https://github.com/dolev146/Politi-Cal/tree/main/app/src/main/java/com/example/politi_cal
这是导航文件 我只是使用答案中描述的概念来传递屏幕作为参数
类似的东西,抽屉包裹内容屏幕
composable(route = Screen.AdminOnlyScreen.route) {
DrawerTopBar(navController = navCotroller, screen = { navController ->
// this is the screen that will be drawn after the drawer
// swipe screen
AdminOnlyScreen(navController = navController, auth = auth)
})
}
composable(route = Screen.UserAnalyticsScreen.route) {
DrawerTopBar(navController = navCotroller, screen = { navController ->
// this is the screen that will be drawn after the drawer
// swipe screen
UserAnalyticsScreen(
navController = navController,
auth = auth
)
})
}
// the drawer TopBar should get the navController as a parameter ,
// and the composable screen function that it needs to draw after the drawer
@Composable
fun DrawerTopBar(
navController: NavController,
auth: FirebaseAuth = FirebaseAuth.getInstance(),
screen: @Composable (navController: NavController) -> Unit
) {
var isAdminState by remember {
mutableStateOf(false)
}
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
val context = LocalContext.current
isAdmin(context) {
isAdminState = true
}
var menuContent = mutableListOf(
MenuItem(
id = "search",
title = "Search",
contentDescription = "Go to Search screen",
icon = Icons.Default.Search
),
// MenuItem(
// id = "swipe",
// title = "Swipe",
// contentDescription = "Go to Swipe screen",
// icon = Icons.Default.Home
// ),
// MenuItem(
// id = "preferences",
// title = "Preferences",
// contentDescription = "Go to Preferences screen",
// icon = Icons.Default.Settings
// ),
// MenuItem(
// id = "logout",
// title = "Logout",
// contentDescription = "Go to Logout screen",
// icon = Icons.Default.ExitToApp
// ),
// MenuItem(
// id = "user analytics",
// title = "User Analytics",
// contentDescription = "Go to User Analytics screen",
// icon = Icons.Default.MoreVert
// )
)
if (isAdminState) {
menuContent.add(
MenuItem(
id = "user analytics",
title = "Analytics",
contentDescription = "Go to User Analytics screen",
icon = Icons.Default.MoreVert
)
)
menuContent.add(
MenuItem(
id = "add celeb",
title = "Add Celeb",
contentDescription = "Go to User profile screen",
icon = Icons.Default.Add
)
)
menuContent.add(
MenuItem(
id = "admin analytics",
title = "Admin Analytics",
contentDescription = "Go to Admin Analytics screen",
icon = Icons.Default.MoreVert
)
)
menuContent.add(
MenuItem(
id = "admin user management",
title = "User Search",
contentDescription = "Go to Admin User Management screen",
icon = Icons.Default.MoreVert
)
)
menuContent.add(
MenuItem(
id = "logout",
title = "Logout",
contentDescription = "Go to Logout screen",
icon = Icons.Default.ExitToApp
)
)
} else {
// this is user menu
menuContent.add(
MenuItem(
id = "swipe",
title = "Swipe",
contentDescription = "Go to Swipe screen",
icon = Icons.Default.Home
)
)
menuContent.add(
MenuItem(
id = "user analytics",
title = "Analytics",
contentDescription = "Go to User Analytics screen",
icon = Icons.Default.MoreVert
)
)
menuContent.add(
MenuItem(
id = "preferences",
title = "Preferences",
contentDescription = "Go to Preferences screen",
icon = Icons.Default.Settings
)
)
menuContent.add(
MenuItem(
id = "my profile",
title = "My Profile",
contentDescription = "Go to User profile screen",
icon = Icons.Default.Person
)
)
menuContent.add(
MenuItem(
id = "logout",
title = "Logout",
contentDescription = "Go to Logout screen",
icon = Icons.Default.ExitToApp
)
)
}
Scaffold(
drawerGesturesEnabled = scaffoldState.drawerState.isOpen,
scaffoldState = scaffoldState,
topBar = {
AppBar(onNavigationIconClick = {
scope.launch {
scaffoldState.drawerState.open()
}
})
},
drawerContent = {
DrawerHeader()
DrawerBody(items = menuContent, onItemClick = {
when (it.id) {
"swipe" -> {
navController.navigate(Screen.SwipeScreen.route)
}
"preferences" -> {
navController.navigate(Screen.PreferenceScreen2.route)
}
"user profile" -> {
navController.navigate(Screen.UserProfileScreen.route)
}
"add celeb" -> {
navController.navigate(Screen.AddCelebScreen.route)
}
"user analytics" -> {
navController.navigate(Screen.UserAnalyticsScreen.route)
}
"logout" -> {
// auth.signOut()
navController.navigate(Screen.SplashScreen.route)
}
"search" -> {
navController.navigate(Screen.SearchScreen.route)
}
"my profile" ->{
navController.navigate(Screen.UserProfileScreen.route)
}
"admin only" -> {
// check that the user is admin
// if not, show a message
// if yes, navigate to the admin only screen
if (isAdminState) {
navController.navigate(Screen.AdminOnlyScreen.route)
} else {
// show a message
Toast.makeText(context, "You are not an admin", Toast.LENGTH_SHORT)
.show()
}
}
"admin analytics" -> {
navController.navigate(Screen.AdminAnalyticsMenuScreen.route)
}
"admin user management" -> {
navController.navigate(Screen.AdminUserManagementScreen.route)
}
}
})
}) {
screen(navController = navController)
}
}
观看链接中的完整代码,如果您喜欢我的解决方案,请点赞:)享受编码的乐趣
评论
Column