news 2026/6/10 15:13:20

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/6/8 13:26:07

华为坚决清仓,从3699元降至1954元,256GB+100W闪充+鸿蒙OS

鸿蒙harmonyos官网 手机行业中绝大多数大品牌的新机,阿维都会第一时间写文章分享出来,但是12月22号的华为nova15系列手机发布后,阿维并没有写文章,因为确实不太推荐粉丝们购买这一新机,不是说这一新机的体验很差&#…

作者头像 李华
网站建设 2026/6/10 11:38:19

基于PyTorch的腾讯HunyuanOCR界面推理部署步骤详解

基于PyTorch的腾讯HunyuanOCR界面推理部署步骤详解 在智能文档处理需求爆发式增长的今天,企业对OCR系统的期待早已超越“把图片变文字”的初级阶段。我们看到越来越多的应用场景——从银行票据自动录入、跨境电商多语言商品识别,到视频平台实时字幕提取—…

作者头像 李华
网站建设 2026/6/10 11:40:29

华为HCIP/HCSE、H3CSE通关经验浅谈

分享一波近期学员的战绩,共同探讨下高级认证备考策略。 华为HCIP-Datacom: 884分,路由交换基础扎实。 华为HCSE-Presales(金融/传输/企业): 均分850左右,对行业解决方案理解深刻。 新华三GB0-392 (H3CSE): 840分&#…

作者头像 李华
网站建设 2026/6/10 13:32:35

奢侈品真假辨别系统:HunyuanOCR比对品牌LOGO与序列号信息

奢侈品真假辨别系统:HunyuanOCR比对品牌LOGO与序列号信息 在二手奢侈品市场交易额突破千亿元的今天,一个看似普通的LV手袋内标照片,可能隐藏着数万元的真伪博弈。买家上传一张模糊的标签图,平台需要在3秒内判断这是否是高仿A货——…

作者头像 李华
网站建设 2026/6/7 22:47:55

AI竞赛题目灵感来源:设计‘复杂文档识别’任务使用HunyuanOCR评分

设计“复杂文档识别”任务使用HunyuanOCR评分 在金融、政务和跨境电商的日常运营中,企业每天要处理成千上万张扫描发票、合同、身份证件等非结构化文档。这些文件格式多样、语言混杂、版式复杂,传统OCR系统往往力不从心——检测不准、识别错乱、字段抽取…

作者头像 李华