Android Jetpack Compose - ModalNavigationDrawer、NavigationRail、PullToRefreshBox

一、ModalNavigationDrawer(抽屉式导航栏)

  1. 使用 drawerContent,提供 ModalDrawerSheet(提供抽屉式导航栏的内容)。可以通过从侧边滑动或点击按钮来打开抽屉式导航栏
kotlin 复制代码
var selectedItemIndex by remember { mutableStateOf(0) }

ModalNavigationDrawer(
    drawerContent = {
        ModalDrawerSheet {
            Text("抽屉式导航栏", modifier = Modifier.padding(16.dp))
            HorizontalDivider()
            NavigationDrawerItem(
                icon = { Icon(Icons.Filled.Home, contentDescription = null) },
                label = { Text("Home") },
                selected = selectedItemIndex == 0,
                onClick = { selectedItemIndex = 0 }
            )
            NavigationDrawerItem(
                icon = { Icon(Icons.Filled.Call, contentDescription = null) },
                label = { Text("Call") },
                selected = selectedItemIndex == 1,
                onClick = { selectedItemIndex = 1 }
            )
            NavigationDrawerItem(
                icon = { Icon(Icons.Filled.Email, contentDescription = null) },
                label = { Text("Email") },
                selected = selectedItemIndex == 2,
                onClick = { selectedItemIndex = 2 }
            )
            NavigationDrawerItem(
                icon = { Icon(Icons.Filled.Person, contentDescription = null) },
                label = { Text("Person") },
                selected = selectedItemIndex == 3,
                onClick = { selectedItemIndex = 3 }
            )
        }
    }
) {}
  1. 控制抽屉式导航栏的打开和关闭,使用 DrawerState,它提供了 open 与 close 方法
kotlin 复制代码
var selectedItemIndex by remember { mutableStateOf(0) }

val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
val scope = rememberCoroutineScope()

ModalNavigationDrawer(
    drawerState = drawerState,
    drawerContent = {
        ModalDrawerSheet {
            Text("抽屉式导航栏", modifier = Modifier.padding(16.dp))
            HorizontalDivider()
            NavigationDrawerItem(
                icon = { Icon(Icons.Filled.Home, contentDescription = null) },
                label = { Text("Home") },
                selected = selectedItemIndex == 0,
                onClick = {
                    selectedItemIndex = 0
                    scope.launch {
                        drawerState.close()
                    }
                }
            )
            NavigationDrawerItem(
                icon = { Icon(Icons.Filled.Call, contentDescription = null) },
                label = { Text("Call") },
                selected = selectedItemIndex == 1,
                onClick = {
                    selectedItemIndex = 1
                    scope.launch {
                        drawerState.close()
                    }
                }
            )
            NavigationDrawerItem(
                icon = { Icon(Icons.Filled.Email, contentDescription = null) },
                label = { Text("Email") },
                selected = selectedItemIndex == 2,
                onClick = {
                    selectedItemIndex = 2
                    scope.launch {
                        drawerState.close()
                    }
                }
            )
            NavigationDrawerItem(
                icon = { Icon(Icons.Filled.Person, contentDescription = null) },
                label = { Text("Person") },
                selected = selectedItemIndex == 3,
                onClick = {
                    selectedItemIndex = 3
                    scope.launch {
                        drawerState.close()
                    }
                }
            )
        }
    }
) {
    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center,
    ) {
        Button(
            onClick = {
                scope.launch {
                    drawerState.open()
                }
            }
        ) {
            Text("打开抽屉式导航栏")
        }
    }
}
kotlin 复制代码
var selectedItemIndex by remember { mutableStateOf(0) }

val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
val scope = rememberCoroutineScope()

ModalNavigationDrawer(
    drawerState = drawerState,
    gesturesEnabled = false,
    drawerContent = {
        ModalDrawerSheet {
            Text("抽屉式导航栏", modifier = Modifier.padding(16.dp))
            HorizontalDivider()
            NavigationDrawerItem(
                icon = { Icon(Icons.Filled.Home, contentDescription = null) },
                label = { Text("Home") },
                selected = selectedItemIndex == 0,
                onClick = {
                    selectedItemIndex = 0
                    scope.launch {
                        drawerState.close()
                    }
                }
            )
            NavigationDrawerItem(
                icon = { Icon(Icons.Filled.Call, contentDescription = null) },
                label = { Text("Call") },
                selected = selectedItemIndex == 1,
                onClick = {
                    selectedItemIndex = 1
                    scope.launch {
                        drawerState.close()
                    }
                }
            )
            NavigationDrawerItem(
                icon = { Icon(Icons.Filled.Email, contentDescription = null) },
                label = { Text("Email") },
                selected = selectedItemIndex == 2,
                onClick = {
                    selectedItemIndex = 2
                    scope.launch {
                        drawerState.close()
                    }
                }
            )
            NavigationDrawerItem(
                icon = { Icon(Icons.Filled.Person, contentDescription = null) },
                label = { Text("Person") },
                selected = selectedItemIndex == 3,
                onClick = {
                    selectedItemIndex = 3
                    scope.launch {
                        drawerState.close()
                    }
                }
            )
        }
    }
) {
    Scaffold(
        topBar = {
            TopAppBar(
                colors = topAppBarColors(
                    containerColor = MaterialTheme.colorScheme.primaryContainer,
                    titleContentColor = MaterialTheme.colorScheme.primary,
                ),
                title = {
                    IconButton(
                        onClick = {
                            scope.launch {
                                drawerState.open()
                            }
                        }
                    ) {
                        Icon(Icons.Default.MoreVert, contentDescription = "MoreVert")
                    }
                }
            )
        },
    ) { innerPadding ->
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(innerPadding),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center,
        ) {
            Text("内容区域")
        }
    }
}

二、NavigationRail(侧边导航栏)

kotlin 复制代码
var selectedItemIndex by remember { mutableStateOf(0) }

NavigationRail {
    NavigationRailItem(
        icon = { Icon(Icons.Filled.Home, contentDescription = null) },
        label = { Text("Home") },
        selected = selectedItemIndex == 0,
        onClick = { selectedItemIndex = 0 }
    )
    NavigationRailItem(
        icon = { Icon(Icons.Filled.Call, contentDescription = null) },
        label = { Text("Call") },
        selected = selectedItemIndex == 1,
        onClick = { selectedItemIndex = 1 }
    )
    NavigationRailItem(
        icon = { Icon(Icons.Filled.Email, contentDescription = null) },
        label = { Text("Email") },
        selected = selectedItemIndex == 2,
        onClick = { selectedItemIndex = 2 }
    )
    NavigationRailItem(
        icon = { Icon(Icons.Filled.Person, contentDescription = null) },
        label = { Text("Person") },
        selected = selectedItemIndex == 3,
        onClick = { selectedItemIndex = 3 }
    )
}
kotlin 复制代码
var selectedItemIndex by remember { mutableStateOf(0) }

Row(
    modifier = Modifier.fillMaxSize()
) {
    NavigationRail {
        NavigationRailItem(
            icon = { Icon(Icons.Filled.Home, contentDescription = null) },
            label = { Text("Home") },
            selected = selectedItemIndex == 0,
            onClick = { selectedItemIndex = 0 }
        )
        NavigationRailItem(
            icon = { Icon(Icons.Filled.Call, contentDescription = null) },
            label = { Text("Call") },
            selected = selectedItemIndex == 1,
            onClick = { selectedItemIndex = 1 }
        )
        NavigationRailItem(
            icon = { Icon(Icons.Filled.Email, contentDescription = null) },
            label = { Text("Email") },
            selected = selectedItemIndex == 2,
            onClick = { selectedItemIndex = 2 }
        )
        NavigationRailItem(
            icon = { Icon(Icons.Filled.Person, contentDescription = null) },
            label = { Text("Person") },
            selected = selectedItemIndex == 3,
            onClick = { selectedItemIndex = 3 }
        )
    }

    Column(
        modifier = Modifier
            .fillMaxHeight()
            .weight(1f),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text("内容区域")
    }
}
kotlin 复制代码
data class NavItem(
    val title: String,
    val icon: ImageVector,
)

val navItems = listOf(
    NavItem("Home", Icons.Filled.Home),
    NavItem("Call", Icons.Filled.Call),
    NavItem("Email", Icons.Filled.Email),
    NavItem("Person", Icons.Filled.Person)
)

var selectedItemIndex by remember { mutableStateOf(0) }

Row(
    modifier = Modifier.fillMaxSize()
) {
    NavigationRail {
        navItems.forEachIndexed { index, item ->
            NavigationRailItem(
                icon = { Icon(item.icon, contentDescription = item.title) },
                label = { Text(item.title) },
                selected = selectedItemIndex == index,
                onClick = { selectedItemIndex = index },
            )
        }
    }

    Column(
        modifier = Modifier
            .fillMaxHeight()
            .weight(1f),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        when (selectedItemIndex) {
            0 -> Text("Home")
            1 -> Text("Call")
            2 -> Text("Email")
            3 -> Text("Person")
        }
    }
}

三、PullToRefreshBox(下拉刷新)

1、基本介绍
  • PullToRefreshBox 组件用于实现下拉刷新,该组件可以包裹可滚动内容,关键参数如下
  1. isRefreshing:指示刷新操作是否正在进行

  2. onRefresh:当发起刷新时执行的函数

2、演示
kotlin 复制代码
var items by remember { mutableStateOf(List(5) { "第 ${it + 1} 项" }) }
val scope = rememberCoroutineScope()

var isRefreshing by remember { mutableStateOf(false) }

PullToRefreshBox(
    modifier = Modifier.fillMaxSize(),
    isRefreshing = isRefreshing,
    onRefresh = {
        isRefreshing = true
        scope.launch {
            delay(1500)
            items = List((1..10).random()) { "新数据 ${it + 1}" }
            isRefreshing = false
        }
    }
) {
    LazyColumn(
        modifier = Modifier.fillMaxSize(),
        contentPadding = PaddingValues(16.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        items(items) { item ->
            Card(
                modifier = Modifier.fillMaxWidth(),
                colors = CardDefaults.cardColors(
                    containerColor = MaterialTheme.colorScheme.surfaceVariant
                )
            ) {
                Text(
                    text = item,
                    modifier = Modifier.padding(16.dp),
                    style = MaterialTheme.typography.bodyLarge
                )
            }
        }
    }
}
相关推荐
youyou-06063 分钟前
AUTOSAR‑COM 常见问题 QA (1)
java·linux·服务器·单片机·汽车
谢亮_vipxieliang6 分钟前
ValidX时间段验证详解:ISO 8601标准与简化格式
java·spring boot·后端·spring·spring cloud·hibernate
Lsetea7 分钟前
Java 请求 HTTPS 报 PKIX path building failed:从证书链到 truststore 的完整排查
java·https·ssl证书·keytool·truststore
蓝桉柒71 小时前
java判断语句
java·开发语言
Zane19941 小时前
String::compareTo凭什么能当参数传?方法引用的四种形式讲透
java·后端
杉氧1 小时前
RN 性能调优指南:重渲染(Re-renders)控制与长列表(FlatList)优化
android·前端·react native
Coffeeee1 小时前
claude-video 一个让你的Agent拥有看视频能力的Skill
android·人工智能·aigc
青山木1 小时前
Hot 100 --- 打家劫舍
java·数据结构·算法·leetcode·动态规划
敲代码的嘎仔1 小时前
28届后端开发-百人小厂面试题
java·后端·面试·程序员·秋招·实习·转正
Bs_MoneyMagnet1 小时前
基于springboot+vue的爱心众筹系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring·管理系统