news 2026/4/16 19:01:55

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/16 12:27:28

流量分析_SnakeBackdoor-4

SnakeBackdoor-4题目4提示上传了一个二进制后门,要求我们找到木马进程执行的本体文件名称。在SnakeBackdoor-2~3中已经拿到了核心密钥 RC4_SECRET bv1p3r_5tr1k3_k3y,这道题的本质就是利用密钥解密流量,还原攻击者的操作记录。攻击者上传并执…

作者头像 李华
网站建设 2026/4/16 14:02:35

API设计自动化:接口生成与优化

API设计自动化:接口生成与优化 关键词:API设计自动化、接口生成、接口优化、自动化工具、代码生成 摘要:本文深入探讨了API设计自动化中的接口生成与优化相关技术。首先介绍了API设计自动化的背景,包括目的、预期读者、文档结构和术语表。接着阐述了核心概念与联系,通过文…

作者头像 李华
网站建设 2026/4/16 12:23:19

计算机视觉课程实验设计:基于HunyuanOCR开展OCR原理教学

计算学视觉课程实验设计:基于HunyuanOCR开展OCR原理教学 在高校计算机视觉教学中,如何让学生既理解OCR的核心原理,又能快速动手实践,一直是个挑战。传统方法往往陷入两难:要么让学生从零实现检测与识别模块&#xff0…

作者头像 李华
网站建设 2026/4/15 16:22:14

物流快递面单自动录入:HunyuanOCR提高分拣中心工作效率

物流快递面单自动录入:HunyuanOCR如何重塑分拣中心效率 在每天处理数十万包裹的快递分拣中心,时间就是生命。一个运单号识别慢了半秒,整条流水线就可能积压;一次地址信息录错,客户投诉就会接踵而至。传统靠人工“看图打…

作者头像 李华
网站建设 2026/4/16 16:20:02

ClickHouse 大数据量场景下执行 ALTER TABLE UPDATE问题(ClickHouse 里,数据最好“只进不出,只增不改”) | ReplicatedReplacingMergeTr

文章目录 ClickHouse 大数据量场景下执行 ALTER TABLE UPDATE问题 问题描述 官方文档 ClickHouse 修改数据的最佳实践(大数据量/生产) 只进不出,只增不改 ReplacingMergeTree:同一主键多版本,取最新 CollapsingMergeTree:用正负记录“抵消” ReplicatedReplacingMergeTre…

作者头像 李华