news 2026/4/13 15:33:33

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/4/11 15:19:40

反激变换器与Buck - boost电路:电力变换的奇妙世界

反激变换器 - Buck-boost电路 在电力电子领域,反激变换器和Buck - boost电路就像两颗璀璨的明星,各自闪耀着独特的光芒,为我们实现各种电源转换需求立下汗马功劳。今天咱们就一起深入这两个神奇电路的世界,探索它们的奥秘。 Buc…

作者头像 李华
网站建设 2026/4/12 2:17:10

继DeepSeek后,量化巨头九坤推40B开源硬刚Claude 4.5,实测结果却反转

00. 引言 说实话,这两年追开源模型,我的心态已经从最初的“卧槽牛逼”变成了现在的“审美疲劳”。 每周都有新模型号称“拳打GPT,脚踢Claude”,结果实测,翻车的不少。但就在昨天,我在刷推特(X)的时候&…

作者头像 李华
网站建设 2026/4/11 23:47:33

2026年:30年来最好的创业时代

Greg Isenberg,36岁连续创业者,卖掉3家公司,帮助融资数十亿美元,分享了他眼中2026年创业的20个历史性机遇。 技术变革带来的机会: 硬件正在觉醒——开源AI廉价机器人打开无数应用场景。传统SaaS正在崩塌,曾…

作者头像 李华
网站建设 2026/4/12 15:15:55

四大子词分词算法详解

四大子词分词算法详解 1. BPE (Byte Pair Encoding) 原理 BPE是最基础的子词分词算法,通过迭代地合并最频繁出现的字符对来构建词表。 训练过程 输入语料: low: 5次 lower: 2次 newest: 6次 widest: 3次步骤: 初始化:将每个单词拆…

作者头像 李华
网站建设 2026/4/12 17:14:41

xhEditor粘贴微信公众号内容到cms

企业CMS系统Word内容导入功能集成方案 作为山西某IT公司的PHP工程师,近期我负责为企业CMS系统集成Word内容导入功能。该功能预算2万元,需在现有系统基础上无缝集成,支持多种文档格式导入和微信公众号内容粘贴。以下是技术实现方案&#xff1…

作者头像 李华
网站建设 2026/4/13 14:44:20

xhEditor复制word图片到OA平台

企业CMS系统Word内容导入功能集成方案 作为山西某IT公司的PHP工程师,近期我负责为企业CMS系统集成Word内容导入功能。该功能预算2万元,需在现有系统基础上无缝集成,支持多种文档格式导入和微信公众号内容粘贴。以下是技术实现方案&#xff1a…

作者头像 李华