You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Jetpack Compose实现Telegram风格的附件Bottom Sheet?求示例

使用Jetpack Compose实现Telegram风格附件Bottom Sheet

要实现和Telegram一致的附件底部弹窗,我们可以基于Jetpack Compose Material3的ModalBottomSheet组件来构建,以下是完整实现示例:

1. 准备依赖

确保你的项目中引入了Compose Material3相关依赖:

dependencies {
    implementation "androidx.compose.material3:material3:1.2.1"
    implementation "androidx.compose.ui:ui:1.6.1"
    implementation "androidx.compose.ui:ui-tooling-preview:1.6.1"
}

2. 定义附件选项数据结构

先封装每个附件选项的图标和标题:

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.ui.graphics.ImageVector

data class AttachmentOption(
    val icon: ImageVector,
    val title: String
)

3. 实现Bottom Sheet核心内容

构建带网格布局的选项面板,匹配Telegram的两行四列样式:

import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.material.icons.Icons
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp

@Composable
fun TelegramAttachmentSheet(
    onDismissRequest: () -> Unit,
    onOptionSelected: (AttachmentOption) -> Unit
) {
    // 模拟Telegram的附件选项列表
    val options = listOf(
        AttachmentOption(Icons.Default.Camera, "拍照"),
        AttachmentOption(Icons.Default.Photo, "相册"),
        AttachmentOption(Icons.Default.FilePresent, "文件"),
        AttachmentOption(Icons.Default.LocationOn, "位置"),
        AttachmentOption(Icons.Default.Mic, "语音"),
        AttachmentOption(Icons.Default.ContactPage, "联系人"),
        AttachmentOption(Icons.Default.Poll, "投票"),
        AttachmentOption(Icons.Default.Gamepad, "游戏")
    )

    Column(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp)
    ) {
        // 右上角关闭按钮
        IconButton(
            onClick = onDismissRequest,
            modifier = Modifier.align(Alignment.End)
        ) {
            Icon(Icons.Default.Close, contentDescription = "关闭弹窗")
        }

        // 四列网格布局
        LazyVerticalGrid(
            columns = GridCells.Fixed(4),
            horizontalArrangement = Arrangement.Center,
            verticalArrangement = Arrangement.spacedBy(16.dp),
            modifier = Modifier.fillMaxWidth()
        ) {
            items(options) { option ->
                Column(
                    horizontalAlignment = Alignment.CenterHorizontally,
                    verticalArrangement = Arrangement.spacedBy(8.dp),
                    modifier = Modifier.clickable {
                        onOptionSelected(option)
                        onDismissRequest()
                    }
                ) {
                    Icon(
                        option.icon,
                        contentDescription = option.title,
                        modifier = Modifier.size(48.dp),
                        tint = MaterialTheme.colorScheme.primary
                    )
                    Text(
                        option.title,
                        style = MaterialTheme.typography.bodySmall,
                        textAlign = TextAlign.Center
                    )
                }
            }
        }
    }
}

4. 在主界面中调用弹窗

通过ModalBottomSheetState控制弹窗的显示与隐藏:

import androidx.compose.floatingactionbutton.FloatingActionButton
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import kotlinx.coroutines.launch

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScreen() {
    val sheetState = rememberModalBottomSheetState(
        skipPartiallyExpanded = true // 跳过半展开状态,直接全屏展开
    )
    val scope = rememberCoroutineScope()
    var showSheet by remember { mutableStateOf(false) }

    Scaffold(
        floatingActionButton = {
            FloatingActionButton(onClick = { showSheet = true }) {
                Icon(Icons.Default.AttachFile, contentDescription = "打开附件面板")
            }
        }
    ) { paddingValues ->
        Box(modifier = Modifier.padding(paddingValues)) {
            // 这里替换成你的主界面内容
            Text(text = "点击右下角按钮打开附件弹窗")
        }

        if (showSheet) {
            ModalBottomSheet(
                onDismissRequest = { showSheet = false },
                sheetState = sheetState,
                shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp) // 设置顶部圆角
            ) {
                TelegramAttachmentSheet(
                    onDismissRequest = { showSheet = false },
                    onOptionSelected = { option ->
                        // 这里添加选项点击后的逻辑,比如跳转相机、相册等
                        println("选中了:${option.title}")
                    }
                )
            }
        }
    }
}

样式适配说明

  • 顶部圆角:通过ModalBottomSheet的shape参数设置,和Telegram弹窗风格一致
  • 图标样式:使用Material Icons匹配Telegram的图标风格,颜色取主题主色调
  • 交互逻辑:点击选项后自动关闭弹窗,符合Telegram的交互习惯

内容的提问来源于stack exchange,提问作者Slava

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 15:28:12