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

Jetpack Compose全屏Dialog在部分设备底部超出屏幕问题排查

Jetpack Compose全屏Dialog底部超出屏幕的适配方案

问题背景

实现的全屏Dialog在Pixel 6模拟器、Android 10设备显示正常,但在Pixel7设备上底部内容超出屏幕。已尝试使用Window Insets、将Box替换为Surface,问题未解决且无报错信息。需保留全屏Dialog形式,明确跨设备适配方法,当前使用最新稳定版Compose依赖。

效果对比:
Pixel7底部超出效果 Pixel6正常显示效果

问题代码:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ListTipListScreen(
    viewModel: MainScreenViewModel,
    onDismissRequest: () -> Unit,
    listId: Int,
    onBackClick: () -> Unit,
) {
    val list = viewModel
        .getListById(listId)
        .collectAsState(null)

    /** 获取对应列表的小费数据 */
    val listTipList by viewModel
        .getAllTipsFromList(listId)
        .collectAsState(emptyList())

    /** 分享小费列表 */
    val context = LocalContext.current

    Dialog(
        onDismissRequest = { onDismissRequest() },
        properties = DialogProperties(
            usePlatformDefaultWidth = false,
            dismissOnBackPress = true,
            decorFitsSystemWindows = false,
            dismissOnClickOutside = false
        )
    ) {
        Scaffold(
            topBar = {
                CenterAlignedTopAppBar(
                    colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
                        containerColor = MaterialTheme.colorScheme.surfaceTint.copy(alpha = 0.1f),
                    ),
                    title = { list.value?.let {
                        Text(text = it.name) }
                    },
                    navigationIcon = {
                        IconButton(
                            onClick = onBackClick
                        ) {
                            Icon(
                                imageVector = Icons.AutoMirrored.Filled.ArrowBack,
                                contentDescription = stringResource(R.string.back)
                            )
                        }
                    }
                )
            },

            /** 添加小费的悬浮按钮 */
            floatingActionButton = {
                FabAdd(
                    onClick = { viewModel.updateShowAddTipValueToListDialog(true) },
                    contentDescription = stringResource(R.string.add_tip_to_list)
                )
            },
            floatingActionButtonPosition = FabPosition.End
        ) { innerPadding ->
            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .padding(innerPadding)
            ) {
                Column(
                    modifier = Modifier
                        .padding(dimensionResource(R.dimen.padding_mid))
                ) {
                    Row(
                        modifier = Modifier.fillMaxWidth(),
                        horizontalArrangement = Arrangement.SpaceBetween,
                        verticalAlignment = Alignment.CenterVertically
                    ) {
                        Text(
                            text = stringResource(R.string.tip_list_title),
                            style = MaterialTheme.typography.titleLarge,
                            modifier = Modifier.padding(dimensionResource(R.dimen.padding_sml))
                        )

                        /** 分享按钮 */
                        Icon(
                            modifier = Modifier
                                .size(24.dp)
                                .clickable {
                                    shareTextWithApps(
                                        title = list.value?.name!!,
                                        content = tipListToString(listTipList),
                                        context = context
                                    )
                                },
                            imageVector = Icons.Default.Share,
                            tint = MaterialTheme.colorScheme.primary,
                            contentDescription = stringResource(R.string.share_tip_list)
                        )
                    }
                    HorizontalDivider(
                        modifier = Modifier
                            .padding(bottom = dimensionResource(R.dimen.padding_mid))
                    )
                    LazyColumn(
                        userScrollEnabled = true
                    ) {

                        /** 展示小费列表项 */
                        itemsIndexed(listTipList) { _, tip ->
                            ListItemComponent(
                                overLineContent = { Text(text = tip.dateCreated) },
                                item = tip,
                                getName = { tip.tipAmount },
                                mainTrailItemInfo = { },
                                listItemTrailingIcon = Icons.Default.DeleteForever,
                                trailingIconContentDescription = stringResource(R.string.delete),
                                onClickTrailingIcon = { viewModel.deleteTip(tip) },
                                onClickLabel = context.getString(R.string.tip_will_be_deleted),
                                modifier = Modifier.height(70.dp)
                            )
                        }
                    }
                }

                /** 添加小费的弹窗 */
                if(viewModel.showAddTipValueToListDialog) {
                    AddTipValueToListDialog(
                        viewModel = viewModel,
                        onSaveRequest = {
                            viewModel.viewModelScope.launch {
                                viewModel.insertTipValueToList(listId)
                                viewModel.updateShowAddTipValueToListDialog(false)
                            }
                        }
                    )
                }
            }
        }
    }
}

适配方案

1. 正确应用系统Window Insets

Pixel7的底部手势区域会占用屏幕空间,需明确获取并应用导航栏Insets。修改Dialog内部结构,在Scaffold外层添加Insets处理:

Dialog(...) {
    val windowInsets = WindowInsets.systemBars
    Box(
        modifier = Modifier
            .fillMaxSize()
            .windowInsetsPadding(windowInsets)
    ) {
        Scaffold(...) { innerPadding ->
            // 原有内容,innerPadding需保留以适配Scaffold自身内边距
        }
    }
}

2. 调整DialogProperties参数

当前设置decorFitsSystemWindows = false会让Dialog忽略系统Insets,可改为true,让系统自动处理Insets,或结合手动Insets处理使用:

properties = DialogProperties(
    usePlatformDefaultWidth = false,
    dismissOnBackPress = true,
    decorFitsSystemWindows = true, // 修改此处
    dismissOnClickOutside = false
)

3. 限制LazyColumn高度

当前LazyColumn未设置高度限制,导致内容可能超出屏幕。添加fillMaxHeight()确保它在可用空间内滚动:

LazyColumn(
    modifier = Modifier.fillMaxHeight(),
    userScrollEnabled = true
) {
    // 原有item内容
}

4. 优化内边距组合

Box已应用innerPadding,Column又添加了全局padding,可能导致垂直空间被挤压。调整Column的padding为仅水平方向:

Column(
    modifier = Modifier
        .padding(horizontal = dimensionResource(R.dimen.padding_mid))
) {
    // 原有内容
}

5. 单独处理底部导航栏Insets

如果只需要处理底部手势区域,可单独使用WindowInsets.navigationBars:

val navigationInsets = WindowInsets.navigationBars
Box(
    modifier = Modifier
        .fillMaxSize()
        .windowInsetsPadding(navigationInsets)
) {
    // Scaffold内容
}

总结

优先尝试正确应用Window Insets和限制LazyColumn高度,这两个是全屏Dialog适配的核心点。可根据实际效果组合使用上述方案,解决Pixel7等大比例屏幕设备的底部内容溢出问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 05:14:49