使用 Jetpack Compose 中的导航抽屉在可组合项之间导航

2024-05-07

我正在尝试在 jetpack compose 中为抽屉图标/文本字段设置导航,但不确定如何正确执行。如何设置导航,以便每当我单击其中一个图标时,我都会导航到该可组合屏幕?这是目前我的主抽屉布局:


@Composable
fun MainDrawer() {

    val scaffoldState = rememberScaffoldState()
    val scope = rememberCoroutineScope()
    Scaffold(
        scaffoldState = scaffoldState,
        topBar = {
            AppBar(
                onNavigationIconClick = {
                    scope.launch {
                        scaffoldState.drawerState.isOpen
                    }
                }
            )
        },
        drawerContent = {
            DrawerHeader()
            DrawerBody(
                items = listOf(
                    MenuItem(

                        id = "item1",
                        title = "item1",
                        contentDescription = "Go to item1 screen",
                        icon = Icons.Default.Home
                    ),
                    MenuItem(
                        id = "item2",
                        title = "item2",
                        contentDescription = "Go to item2 screen",
                        icon = Icons.Default.Settings
                    ),
                    MenuItem(
                        id = "item3",
                        title = "item3",
                        contentDescription = "Ge to item3",
                        icon = Icons.Default.Info
                    ),
                    MenuItem(
                        id = "item4",
                        title = "item4",
                        contentDescription = "Go to Your item4",
                        icon = Icons.Default.Info
                    ),
                    MenuItem(
                        id = "item5",
                        title = "item5",
                        contentDescription = "Your item5",
                        icon = Icons.Default.Info
                    ),
                    MenuItem(
                        id = "item6",
                        title = "item6",
                        contentDescription = "Your item6",
                        icon = Icons.Default.Info
                    ),
                    MenuItem(
                        id = "item7",
                        title = "item7",
                        contentDescription = "item7",
                        icon = Icons.Default.Info
                    ),
                    MenuItem(
                        id = "item8",
                        title = "item8",
                        contentDescription = "item8",
                        icon = Icons.Default.Info
                    ),
                )
            ) {
                println("Clicked on ${it.title}")
            }
        }
    ) {

    }
}

抽屉主体: 这包含了 body 的元素

@Composable
fun DrawerBody(
    items: List<MenuItem>,
    modifier: Modifier = Modifier,
    itemTextStyle: TextStyle = TextStyle(fontSize = 18.sp),
    onItemClick: (MenuItem) -> Unit
) {
    LazyColumn(modifier) {
        items(items) { item ->
            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .clickable {
                        onItemClick(item)
                    }
                    .padding(16.dp)
            ) {
                Icon(
                    imageVector = item.icon,
                    contentDescription = item.contentDescription
                )
                Spacer(modifier = Modifier.width(16.dp))
                Text(
                    text = item.title,
                    style = itemTextStyle,
                    modifier = Modifier.weight(1f)
                )
            }
        }

    }

}


我设法解决了这个问题。其工作原理如下:https://gyazo.com/4c32e855becff72f8979650545ad7f39 https://gyazo.com/4c32e855becff72f8979650545ad7f39

我就是这样做的:

  1. 首先将依赖项添加到您的项目中:
 // Navigation with Compose
    implementation "androidx.navigation:navigation-compose:2.5.0"

    // Modal Drawer Layout
    implementation "androidx.drawerlayout:drawerlayout:1.1.1"

 // Coroutines
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"

  1. 首先为应用程序创建 TopAppBar。这是以下代码:

@Composable
fun TopBar(scope: CoroutineScope, scaffoldState: ScaffoldState) {
    TopAppBar(
        title = { Text(text = stringResource(R.string.app_name), fontSize = 18.sp) },
        navigationIcon = {
            IconButton(onClick = {
                scope.launch {
                    scaffoldState.drawerState.open()
                }
            }) {
                Icon(Icons.Filled.Menu, "")
            }
        },
        backgroundColor = colorResource(id = R.color.purple_200),
        contentColor = Color.White
    )
}
  1. 接下来,创建一个密封类。这个类将代表你想要放在抽屉里的物品。我举以下例子:
sealed class NavDrawerItem(var route: String, var icon: Int, var title: String) {
    object Add : NavDrawerItem("add", android.R.drawable.ic_menu_add, "Add")
    object Edit : NavDrawerItem("edit", android.R.drawable.ic_menu_edit, "Edit")
    object Search : NavDrawerItem("search", android.R.drawable.ic_menu_search, "Search")
    object Location : NavDrawerItem("location", android.R.drawable.ic_menu_mylocation, "Location")
    object Preferences : NavDrawerItem("preferences", android.R.drawable.ic_menu_preferences, "Preferences")
}
  1. 现在,创建荧光笔。当抽屉中的某个项目被按下时,这将突出显示被按下的项目。
@Composable
fun DrawerItem(item: NavDrawerItem, selected: Boolean, onItemClick: (NavDrawerItem) -> Unit) {
    val background = if (selected) R.color.purple_200 else android.R.color.transparent
    Row(
        verticalAlignment = Alignment.CenterVertically,
        modifier = Modifier
            .fillMaxWidth()
            .clickable(onClick = { onItemClick(item) })
            .height(45.dp)
            .background(colorResource(id = background))
            .padding(start = 10.dp)
    ) {
        Image(
            painter = painterResource(id = item.icon),
            contentDescription = item.title,
            colorFilter = ColorFilter.tint(Color.White),
            contentScale = ContentScale.Fit,
            modifier = Modifier
                .height(35.dp)
                .width(35.dp)
        )
        Spacer(modifier = Modifier.width(7.dp))
        Text(
            text = item.title,
            fontSize = 18.sp,
            color = Color.White
        )
    }
}
  1. 在这里,我们为各个项目创建每个屏幕。每个项目有 1 个可组合屏幕。我创建了一个简单快速的屏幕,但您可以在这里创建自己的屏幕。
@Composable
fun AddScreen() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(colorResource(id = R.color.myColor))
            .wrapContentSize(Alignment.Center)
    ) {
        Text(
            text = "Add Screen",
            fontWeight = FontWeight.Bold,
            color = Color.White,
            modifier = Modifier.align(Alignment.CenterHorizontally),
            textAlign = TextAlign.Center,
            fontSize = 25.sp
        )
    }
}

@Composable
fun EditScreen() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(colorResource(id = R.color.myOrange))
            .wrapContentSize(Alignment.Center)
    ) {
        Text(
            text = "Edit Screen",
            fontWeight = FontWeight.Bold,
            color = Color.White,
            modifier = Modifier.align(Alignment.CenterHorizontally),
            textAlign = TextAlign.Center,
            fontSize = 25.sp
        )
    }
}

@Composable
fun SearchScreen() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(colorResource(id = R.color.purple_500))
            .wrapContentSize(Alignment.Center)
    ) {
        Text(
            text = "Search Screen",
            fontWeight = FontWeight.Bold,
            color = Color.White,
            modifier = Modifier.align(Alignment.CenterHorizontally),
            textAlign = TextAlign.Center,
            fontSize = 25.sp
        )
    }
}

@Composable
fun LocationScreen() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(colorResource(id = R.color.myGreen))
            .wrapContentSize(Alignment.Center)
    ) {
        Text(
            text = "Location Screen",
            fontWeight = FontWeight.Bold,
            color = Color.White,
            modifier = Modifier.align(Alignment.CenterHorizontally),
            textAlign = TextAlign.Center,
            fontSize = 25.sp
        )
    }
}

@Composable
fun PreferencesScreen() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(colorResource(id = R.color.myGreen))
            .wrapContentSize(Alignment.Center)
    ) {
        Text(
            text = "Preference Screen",
            fontWeight = FontWeight.Bold,
            color = Color.White,
            modifier = Modifier.align(Alignment.CenterHorizontally),
            textAlign = TextAlign.Center,
            fontSize = 25.sp
        )
    }
}
  1. 现在我们需要使用 navcontroller 和 navHostController 创建实际的导航。我们通过以下方式做到这一点:
@Composable
fun ComposeNavigation(navController: NavHostController) {
    NavHost(navController, startDestination = NavDrawerItem.Add.route) {
        composable(NavDrawerItem.Add.route) {
            AddScreen()
        }
        composable(NavDrawerItem.Edit.route) {
            EditScreen()
        }
        composable(NavDrawerItem.Search.route) {
            SearchScreen()
        }
        composable(NavDrawerItem.Location.route) {
            LocationScreen()
        }
        composable(NavDrawerItem.Preferences.route) {
            PreferencesScreen()
        }
    }
}

  1. 之后,使用所有项目、协程和 navbackstack 创建 DrawerLayout。
@Composable
fun DrawerLayout(scope: CoroutineScope, scaffoldState: ScaffoldState, navController: NavController) {
    val items = listOf(
        NavDrawerItem.Add,
        NavDrawerItem.Edit,
        NavDrawerItem.Search,
        NavDrawerItem.Location,
        NavDrawerItem.Preferences
    )
    Column {
// Header
        Image(
            painter = painterResource(id = R.drawable.ic_launcher_foreground),
            contentDescription = R.drawable.ic_launcher_foreground.toString(),
            modifier = Modifier
                .height(100.dp)
                .fillMaxWidth()
                .padding(10.dp)
        )
        Spacer(
            modifier = Modifier
                .fillMaxWidth()
                .height(5.dp)
        )
        val navBackStackEntry by navController.currentBackStackEntryAsState()
        val currentRoute = navBackStackEntry?.destination?.route
        items.forEach { item ->
            DrawerItem(item = item, selected = currentRoute == item.route, onItemClick = {
                navController.navigate(item.route) {
                    navController.graph.startDestinationRoute?.let { route ->
                        popUpTo(route) {
                            saveState = true
                        }
                    }
                    launchSingleTop = true
                    restoreState = true
                }
                scope.launch {
                    scaffoldState.drawerState.close()
                }
            })
        }
    }
}

  1. 最后,我们创建将作为我们应用程序的主框架的 mainLayout。这里将使用顶栏和抽屉内容的脚手架:
@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
@Composable
fun MainLayout() {

    val scaffoldState = rememberScaffoldState(rememberDrawerState(DrawerValue.Closed))
    val scope = rememberCoroutineScope()
    val navController = rememberNavController()

    Scaffold(
        scaffoldState = scaffoldState,
        topBar = { TopBar(scope = scope, scaffoldState = scaffoldState) },
        drawerBackgroundColor = colorResource(id = R.color.myColor),
        drawerContent = {
            DrawerLayout(scope = scope, scaffoldState = scaffoldState, navController = navController)
        },
    ) {

        ComposeNavigation(navController = navController)
    }
}

希望这可以帮助任何正在寻找功能性导航抽屉的人!如果这对您有用,请随意给它一个向上箭头。快乐编码!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Jetpack Compose 中的导航抽屉在可组合项之间导航 的相关文章

  • 与 Admob 广告单元 ID 混淆

    我跟着tutorial https developers google com admob android quick start在我的应用程序中创建广告横幅 到目前为止 这有效 我可以看到测试广告 但是 本教程指示我在两个不同的位置使用两
  • 共同的偏好不断消失

    我正在使用共享首选项来存储我的应用程序的登录凭据 除了一个用户之外 一切正常 一段时间后 共享偏好似乎会以某种方式重置或清除 我已针对该用户调整了我的应用程序 使其不再清除他的共享偏好设置 这样我就可以确定这不是我的应用程序的错 但即使在这
  • 菜单未显示在应用程序中

    由于某种原因 我的操作菜单在我的 Android Studio 应用程序中消失了 我正在按照教程学习如何创建 Android 应用程序 但最终遇到了这个问题 我正在使用 atm 的教程 http www raywenderlich com
  • Android:“dp”到“px”转换?

    我正在读这篇文章 http developer android com guide practices screens support html http developer android com guide practices scre
  • 如何将 Java 赋值表达式转换为 Kotlin

    java中的一些东西就像 int a 1 b 2 c 1 if a b c System out print true 现在它应该转换为 kotlin 就像 var a Int 1 var b Int 2 var c Int 1 if a
  • KitKat(及更低版本)设备上的 Android Material Design

    我将在我们学校开发一个 Android 应用程序作为一个项目 我想使用 Google 的新 Material Design 但我知道它仅适用于 Android L 设备 Jack Underwood 最近发布了名为 Today Calend
  • 设置从 Facebook 登录获取用户电子邮件 ID 的权限

    我在用着Facebook 3 0 SDK对于安卓 我必须实施Facebook登录 我正在访问用户的基本信息 例如姓名 用户 ID 但我也想访问用户的电子邮件 我浏览了很多博客和论坛 但不知道该怎么做 我正在使用我自己的 android 按钮
  • 如果我们使用后退按钮退出,为什么 Android 应用程序会重新启动?

    按住主页按钮并返回应用程序时 应用程序不会重新启动 为什么使用后退按钮会重新启动 如果我们使用后退按钮退出 有什么方法可以解决在不重新启动的情况下获取应用程序的问题吗 请帮忙 当您按下Home按钮 应用程序将暂停并保存当前状态 最后应用程序
  • TextView 之间有分隔线

    我正在尝试在 android studio 中创建以下布局 因为我对 android 东西还很陌生 所以我第一次尝试使用 LinearLayout 并认为这可能无法实现 现在我正在尝试使用RelativeLayout 我已经用颜色创建了这个
  • OnClick 事件中的 finish() 如何工作?

    我有一个Activity一键退出Activity 通过layout xml我必须设置OnClick事件至cmd exit调用 this finish 效果很好 public void cmd exit View editLayout thi
  • Firebase:如何在Android应用程序中设置默认通知渠道?

    如何设置default通知渠道通知消息当应用程序在后台运行时会出现什么情况 默认情况下 这些消息使用 杂项 通道 如你看到的在官方文档中 https firebase google com docs cloud messaging andr
  • 从 android 简单上传到 S3

    我在网上搜索了从 android 上传简单文件到 s3 的方法 但找不到任何有效的方法 我认为这是因为缺乏具体步骤 1 https mobile awsblog com post Tx1V588RKX5XPQB TransferManage
  • 使用 Matrix.setPolyToPoly 选择位图上具有 4 个点的区域

    我正在 Android 上使用位图 在使用 4 个点选择位图上的区域时遇到问题 并非所有 4 点组都适合我 在某些情况下 结果只是一个空白位图 而不是裁剪后的位图 如图所示 并且 logcat 中没有任何错误 甚至是内存错误 这是我用来进行
  • 将 JSON 参数从 java 发布到 sinatra 服务

    我有一个 Android 应用程序发布到我的 sinatra 服务 早些时候 我无法读取 sinatra 服务上的参数 但是 在我将内容类型设置为 x www form urlencoded 之后 我能够看到参数 但不完全是我想要的 我在
  • 当手机旋转(方向改变)时如何最好地重新创建标记/折线

    背景 开发一个使用 Android Google Map v2 的本机 Android 应用程序 使用android support v4 app FragmentActivity 在 Android v2 2 上运行 客观的 在更改手机方
  • 保护 APK 中的字符串

    我正在使用 Xamarin 的 Mono for Android 开发一个 Android 应用程序 我目前正在努力使用 Google Play API 添加应用内购买功能 为此 我需要从我的应用程序内向 Google 发送公共许可证密钥
  • Android 如何聚焦当前位置

    您好 我有一个 Android 应用程序 可以在谷歌地图上找到您的位置 但是当我启动该应用程序时 它从非洲开始 而不是在我当前的城市 国家 位置等 我已经在developer android com上检查了信息与位置问题有关 但问题仍然存在
  • 在 Android 中,如何将字符串从 Activity 传递到 Service?

    任何人都可以告诉如何将字符串或整数从活动传递到服务 我试图传递一个整数 setpossition 4 但它不需要 启动时总是需要 0 Service 我不知道为什么我不能通过使用 Service 实例从 Activity 进行操作 publ
  • 无法将 admob 与 firebase iOS/Android 项目链接

    我有两个帐户 A 和 B A 是在 Firebase 上托管 iOS Android unity 手机游戏的主帐户 B 用于将 admob 集成到 iOS Android 手机游戏中 我在尝试将 admob 分析链接到 Firebase 项
  • 在 Google 地图上绘制线条/路径

    我很长一段时间都在忙于寻找如何在 HelloMapView 中的地图上的两个 GPS 点之间画一条线 但没有运气 谁能告诉我该怎么做 假设我使用扩展 MapView 的 HelloMapView 我需要使用叠加层吗 如果是这样 我是否必须重

随机推荐

  • 将图像小部件调整为父级高度但溢出宽度

    我想创建一个图像小部件 其大小适合其父级的高度 但随后根据显示图像的纵横比溢出父级的宽度 我试过了FittedBox和组合LayoutBuilder and SizedOverflowBox 但没有运气 到目前为止 我只能将图像的宽度和高度
  • 在 ttk 进度条中显示百分比

    我正在尝试显示百分比ttk Progressbar当该功能运行时提醒用户已执行的过程的范围以及剩余的内容 我能够显示百分比 但百分比最多23 哪一个是length of my tuple 我怎样才能让它达到100 length of tup
  • FreeMM 与 ShareMem

    我们有很多用 delphi 和 c builder 编写的 dll 库 并使用 sharemem 和 borlndmm dll 3d party 库中的对齐问题迫使我们转向 delphi 2007 中的新内存管理器 有人可以帮我解释一下 共
  • Linux 上的 OpenCL 编译

    我是 OpenCL 的新手 从昨天开始 我尝试使用 OpenCL 进行并行编程 而不是使用我更熟悉且以前体验过的 CUDA 现在我有 NVIDIA GTX 580 GPU Ubuntu Linux 12 04 操作系统和 CUDA SDK
  • 比较java中的数组和索引位置[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 在一次 java 面试中 有人问我如
  • JS - document.getelementbysrc?

    是否可以从 src 属性的值获取元素 没有 DOM 方法可以按属性过滤元素 您需要遍历特定标签的所有元素并过滤掉那些匹配的元素src value function getElementsBySrc srcValue var nodes va
  • pandas:分割字符串和计数值? [复制]

    这个问题在这里已经有答案了 我有一个 pandas 数据集 其中有一列是逗号分隔的字符串 例如1 2 3 10 data id 1 score 9 topics 11 22 30 id 2 score 7 topics 11 18 30 i
  • 如何对 int[] 数组求和[重复]

    这个问题在这里已经有答案了 给定一个数组A of 10 ints 初始化一个名为的局部变量sum并使用循环查找数组中所有数字的总和A 这是我提交的答案 sum 0 while A lt 10 sum sum A 我在这个问题上没有得到任何分
  • 鼠标悬停时 WPF 按钮背景透明度

    我正在尝试更改某些按钮上的鼠标悬停效果 因为它们设置了不同的自定义背景颜色 因此当前将相同浅蓝色的鼠标悬停方案不太适合 我目前得到了这个
  • MVVM 消息传递与 RaisePropertyChanged

    MVVM 消息传递和 RaisePropertyChanged 之间有什么区别 当视图模型 B 中的属性发生更改时 我尝试在视图模型 A 中运行函数 哪种方法更适合使用 消息传递还是 RaisePropertyChanged 广播 谢谢 尼
  • 如何从替换特殊字符的字符串创建 URL?

    我正在尝试从 iframe 内部发出 jsonp 请求 由于某种原因 它似乎不起作用 看到这个question https stackoverflow com questions 20422125 no callback in jsonp
  • Android Socket + ObjectOutputStream 无法正常工作

    我正在开发一个客户端 服务器程序 其中客户端是 Android 设备 服务器有一个从输入流读取对象的侦听器类 我为另一台计算机创建了一个客户端软件 该软件通过本地网络发送一个小对象 计算机到计算机工作得很好 我读取了该对象并打印了内容 但是
  • mongodb 中的 $size 与条件

    我正在使用聚合从两个集合中获取值 一个是文件夹 另一个是检查 我正在获取所有数据 但检查计数为 0 我的代码 mongo folder aggregate lookup from inspections localField id fore
  • UIWebview 中的 NSString

    我有一个NSString和我的项目中的 webView iPhone 的 Objective C 我称之为index html在 webView 及其内部我插入了我的脚本 javascript 如何在脚本中将 NSString 作为 var
  • Servlet 过滤器不适用于容器管理的登录页面

    我正在使用一个Filter在我的所有页面中插入反点击劫持标头 这可以正常工作 但 JBoss EAP 6 3 容器管理的登录页面除外 这是拥有该功能的更重要的页面之一 登录页面根本不会调用过滤器 该页面由http localhost App
  • git推送错误“致命:无法找到'https'的远程帮助程序”

    我添加了远程源 例如 git remote add origin https github com username repo git 当我推送 git 存储库时 出现以下错误 git push u origin master fatal
  • 在 Morphia 中,我如何更新 ArrayList 中的一个嵌入对象

    使用 Mongodb 与 Morphia 确实很陌生 并且看到了许多如何执行此操作的高级答案 如果可能的话我想做简单的并且我有这个 Embedded对象称为 fileObjects其中包含Files对象 我无法更新里面的字段Files 我只
  • 是否有相当于 Windows 8 / winrt / Metro 风格的 wp7 的marketreviewtask?

    我浏览了 MSDN 上的 Store API 和 Launchers 集合 似乎找不到可以在 Marketplace 应用程序中打开应用程序以供用户评分的任务或启动器 正如我们在 Windows Phone 7 中可以轻松做到的那样 htt
  • 当数据未定义或为空时如何使用 Lodash

    在我的应用程序中 如果来自服务的数据未定义或为 null 我的 html 将无法加载 并且会收到 数据未定义 错误 所以我尝试使用lodash 但不知道如何使用它 在我下面的 ts 文件中 this PartService GetDataV
  • 使用 Jetpack Compose 中的导航抽屉在可组合项之间导航

    我正在尝试在 jetpack compose 中为抽屉图标 文本字段设置导航 但不确定如何正确执行 如何设置导航 以便每当我单击其中一个图标时 我都会导航到该可组合屏幕 这是目前我的主抽屉布局 Composable fun MainDraw