news 2026/2/26 15:47:16

Compose笔记(六十六)--ModalNavigationDrawer

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Compose笔记(六十六)--ModalNavigationDrawer

这一节主要了解一下Compose中的ModalNavigationDrawer,在Jetpack Compose开发中,ModalNavigationDrawer是一个用于实现模态导航抽屉的核心组件,它允许用户通过侧滑手势或点击菜单图标触发一个覆盖在主内容之上的抽屉菜单,提供页面切换、功能导航等功能。简单总结如下:

API:
drawerContent:定义抽屉菜单的内容。
drawerState:控制抽屉的打开/关闭状态。
gesturesEnabled:是否启用侧滑手势。
scrimColor:抽屉背景的遮罩层颜色。
content:抽屉外部的主内容。

一般场景:
1 页面导航 通过抽屉菜单切换不同页面
2 功能入口 集中管理应用的核心功能
3 账号管理 提供快速访问账号设置、个人资料的入口

栗子:

import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Home import androidx.compose.material.icons.outlined.Menu import androidx.compose.material.icons.outlined.Message import androidx.compose.material.icons.outlined.Person import androidx.compose.material.icons.outlined.Settings import androidx.compose.material3.DrawerValue import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalDrawerSheet import androidx.compose.material3.ModalNavigationDrawer import androidx.compose.material3.NavigationDrawerItem import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.material3.rememberDrawerState import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable fun ModalNavigationDrawerDemo() { val coroutineScope = rememberCoroutineScope() val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed) data class NavItem( val title: String, val icon: @Composable () -> Unit ) val navItems = remember { listOf( NavItem("首页", { Icon(Icons.Outlined.Home, contentDescription = null) }), NavItem("消息", { Icon(Icons.Outlined.Message, contentDescription = null) }), NavItem("我的", { Icon(Icons.Outlined.Person, contentDescription = null) }), NavItem("设置", { Icon(Icons.Outlined.Settings, contentDescription = null) }) ) } val selectedItemIndex = remember { mutableStateOf(0) } ModalNavigationDrawer( drawerState = drawerState, drawerContent = { ModalDrawerSheet { LazyColumn( modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { items(navItems.size) { index -> val item = navItems[index] NavigationDrawerItem( label = { Text(text = item.title) }, selected = selectedItemIndex.value == index, onClick = { selectedItemIndex.value = index coroutineScope.launch { drawerState.close() } }, icon = item.icon, modifier = Modifier.padding(horizontal = 8.dp) ) } } } }, content = { Scaffold( topBar = { TopAppBar( title = { Text(text = navItems[selectedItemIndex.value].title) }, navigationIcon = { IconButton( onClick = { coroutineScope.launch { drawerState.open() } } ) { Icon(Icons.Outlined.Menu, contentDescription = "打开抽屉") } } ) } ) { innerPadding -> Column( modifier = Modifier .fillMaxSize() .padding(innerPadding) .padding(32.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { Text( text = "当前页面:${navItems[selectedItemIndex.value].title}", style = MaterialTheme.typography.headlineSmall ) Text( text = "可通过左侧手势滑动打开抽屉", style = MaterialTheme.typography.bodyMedium, modifier = Modifier.padding(top = 16.dp) ) } } } ) }
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Home import androidx.compose.material.icons.outlined.Menu import androidx.compose.material.icons.outlined.Message import androidx.compose.material.icons.outlined.Person import androidx.compose.material3.Badge import androidx.compose.material3.DrawerValue import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalDrawerSheet import androidx.compose.material3.ModalNavigationDrawer import androidx.compose.material3.NavigationDrawerItem import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.material3.rememberDrawerState import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable fun ModalNavigationDrawerDemo() { val coroutineScope = rememberCoroutineScope() val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed) data class NavItem( val title: String, val icon: @Composable () -> Unit, val badgeCount: Int? = null ) val navItems = remember { listOf( NavItem("首页", { Icon(Icons.Outlined.Home, contentDescription = null) }), NavItem("消息", { Icon(Icons.Outlined.Message, contentDescription = null) }, 99), // 带99条未读消息 NavItem("我的", { Icon(Icons.Outlined.Person, contentDescription = null) }) ) } val selectedItemIndex = remember { mutableStateOf(0) } ModalNavigationDrawer( drawerState = drawerState, drawerContent = { ModalDrawerSheet( modifier = Modifier.width(280.dp) ) { LazyColumn( modifier = Modifier .fillMaxWidth() .padding(16.dp), verticalArrangement = Arrangement.spacedBy(12.dp) ) { item { Text( text = "我的导航", style = MaterialTheme.typography.titleLarge, modifier = Modifier.padding(horizontal = 8.dp, vertical = 16.dp) ) } items(navItems.size) { index -> val item = navItems[index] NavigationDrawerItem( label = { Text(text = item.title) }, selected = selectedItemIndex.value == index, onClick = { selectedItemIndex.value = index coroutineScope.launch { drawerState.close() } }, icon = item.icon, badge = item.badgeCount?.let { count -> { Badge { Text(text = count.toString(), fontSize = 12.sp) } } }, modifier = Modifier.padding(horizontal = 8.dp) ) } } } }, scrimColor = Color.Gray.copy(alpha = 0.5f), gesturesEnabled = false, content = { Scaffold( topBar = { TopAppBar( title = { Text(text = navItems[selectedItemIndex.value].title) }, navigationIcon = { IconButton( onClick = { coroutineScope.launch { if (drawerState.isOpen) { drawerState.close() } else { drawerState.open() } } } ) { Icon(Icons.Outlined.Menu, contentDescription = "切换抽屉") } } ) } ) { innerPadding -> Column( modifier = Modifier .fillMaxSize() .padding(innerPadding) .padding(32.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { Text( text = "自定义抽屉样式Demo", style = MaterialTheme.typography.headlineSmall ) Text( text = "1. 自定义遮罩颜色\n2. 消息项带99条未读徽章\n3. 禁用手势滑动 \n4. 自定义抽屉宽度", style = MaterialTheme.typography.bodyMedium, modifier = Modifier.padding(top = 16.dp), ) } } } ) }

注意:
1 避免在drawerContent中使用复杂布局或高频更新的组件,可能导致卡顿。
2 drawerState.open()和drawerState.close()是挂起函数,必须在协程作用域。
3 ModalNavigationDrawer需要Compose Material 3支持。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/27 5:09:55

python虚拟环境实践:Conda 环境激活报错及解决

项目场景: 手写表格识别项目 问题描述 报错: $ F:\Anaconda3\Scripts\conda-script.py shell.cmd.exe activate env36environment variables: conda info could not be constructed. KeyError(pkgs_dirs)An unexpected error has occurred. Conda has pr…

作者头像 李华
网站建设 2026/2/22 11:40:44

医院病历电子化加速:门诊处方单文字识别一步到位

医院病历电子化加速:门诊处方单文字识别一步到位 在门诊药房窗口,一位医生递出一张手写处方——字迹潦草、格式不一、中英文混杂。药剂师皱眉逐字辨认,生怕看错剂量;信息系统里却仍需手动录入,耗时又易出错。这样的场景…

作者头像 李华
网站建设 2026/2/24 13:27:37

大数据领域数据服务:实现数据的多维度分析与应用

大数据领域数据服务:实现数据的多维度分析与应用关键词:大数据数据服务、多维度分析、数据应用、维度建模、数据驱动决策摘要:在数字化时代,数据已成为企业的核心资产。本文将从“数据服务”这一枢纽出发,用“超市选品…

作者头像 李华
网站建设 2026/2/23 14:15:53

ONNX格式转换尝试:能否将HunyuanOCR导出为跨框架通用模型?

ONNX格式转换尝试:能否将HunyuanOCR导出为跨框架通用模型? 在当前AI应用加速落地的背景下,一个越来越现实的问题摆在开发者面前:如何让训练好的高性能模型摆脱“只能跑在PyTorch环境”的束缚?尤其是在企业级系统中&am…

作者头像 李华
网站建设 2026/2/27 5:41:14

LaTeX公式识别也行?测试腾讯HunyuanOCR对学术文档的支持能力

LaTeX公式识别也行?测试腾讯HunyuanOCR对学术文档的支持能力 在科研人员日常处理论文、讲义和手稿的数字化过程中,一个反复出现的痛点始终挥之不去:那些密密麻麻的数学公式,一旦经过扫描或截图,几乎总会在OCR工具中“…

作者头像 李华
网站建设 2026/2/24 19:03:57

Bash 脚本中的 ((i++)) || true 表达式详解( set -e 表达式陷阱)

文章目录Bash 脚本中的 ((current_index)) || true 表达式详解set -e 的“表达式陷阱”1.1 什么是 set -e1.2 Bash 中的真值和假值1.3 算术表达式 (( ))为什么需要 || true解决方案:|| true 的作用实战里怎么避免踩坑(推荐几条“习惯用法”)B…

作者头像 李华