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

如何编程设置Android Compose BackdropScaffold的peekHeight

编程设置BackdropScaffold的peekHeight适配AppBar高度方案

核心问题是你当前获取的AppBar尺寸size是MyAppBar组件的内部局部变量,外层BackdropScaffold无法访问,通过Compose状态上提即可实现值的传递,具体步骤如下:

  • 第一步:在BackdropScaffold所在的父Composable作用域中,定义AppBar高度状态与单位转换逻辑
    // 存储AppBar高度的像素值
    var appBarHeightPx by remember { mutableStateOf(0) }
    // 将像素值转换为Dp单位,适配不同屏幕密度
    val appBarHeightDp = with(LocalDensity.current) { appBarHeightPx.toDp() }
    
  • 第二步:改造MyAppBar组件,新增尺寸变化回调,移除内部的局部size变量
    @Composable
    fun MyAppBar(
        backdropRevealed: Boolean,
        onBackdropReveal: (Boolean) -> Unit = {},
        onAppBarMeasured: (IntSize) -> Unit = {} // 新增尺寸上报回调
    ) {
        SmallTopAppBar(
            modifier = Modifier.onSizeChanged { onAppBarMeasured(it) },
            // 以下title、actions等原有逻辑完全不需要修改
            title = {
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.Start,
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    Box(
                        Modifier
                            .width(48.dp)
                            .toggleable(
                                value = backdropRevealed,
                                onValueChange = { onBackdropReveal(it) },
                                indication = rememberRipple(bounded = false, radius = 56.dp),
                                interactionSource = remember { MutableInteractionSource() }
                            ),
                        contentAlignment = Alignment.CenterStart
                    ) {
                        AnimatedContent(
                            targetState = backdropRevealed,
                            transitionSpec = {
                                if (targetState) {
                                    fadeIn(animationSpec = tween(durationMillis = 240, delayMillis = 120, easing = LinearEasing)) with
                                            fadeOut(animationSpec = tween(durationMillis = 120, easing = LinearEasing))
                                } else {
                                    fadeIn(animationSpec = tween(durationMillis = 180, delayMillis = 90, easing = LinearEasing)) with
                                            fadeOut(animationSpec = tween(durationMillis = 90, easing = LinearEasing))
                                }.using(SizeTransform(clip = false))
                            },
                            contentAlignment = Alignment.CenterStart
                        ) { revealed ->
                            if (revealed) {
                                Icon(Icons.Default.Close, contentDescription = "Close")
                            } else {
                                Icon(Icons.Default.Menu, contentDescription = "Menu")
                            }
                        }
                    }
                    Text(
                        text = "My App",
                        style = MaterialTheme.typography.titleMedium,
                        color = MaterialTheme.colorScheme.onSurface
                    )
                }
            },
            actions = {
                IconButton(onClick = { Timber.e("Display Overflow app bar actions") }) {
                    Icon(
                        imageVector = Icons.Rounded.MoreVert,
                        contentDescription = "Localized description"
                    )
                }
            }
        )
    }
    
  • 第三步:实例化AppBar时传入尺寸回调更新状态,给BackdropScaffold的peekHeight赋值转换后的Dp值
    val myAppBar: @Composable () -> Unit = {
        MyAppBar(
            backdropRevealed = backdropRevealed,
            onBackdropReveal = {
                if (!scaffoldState.isAnimationRunning) {
                    backdropRevealed = it
                    scope.launch {
                        if (scaffoldState.isConcealed) {
                            scaffoldState.reveal()
                        } else {
                            scaffoldState.conceal()
                        }
                    }
                }
            },
            onAppBarMeasured { appBarHeightPx = it.height } // 上报AppBar实际高度
        )
    }
    
    BackdropScaffold(
        scaffoldState = scaffoldState,
        gesturesEnabled = false,
        appBar = myAppBar,
        backLayerBackgroundColor = MaterialTheme.colorScheme.secondary,
        backLayerContentColor = MaterialTheme.colorScheme.onSecondary,
        backLayerContent = { ShowcaseBackLayerContent() },
        frontLayerContent = { ShowcaseFrontLayerContent() },
        frontLayerScrimColor = Color.Unspecified,
        peekHeight = appBarHeightDp // 动态适配AppBar高度
    ) {
        // 原有布局内容
    }
    

初始加载时appBarHeightPx默认值为0,AppBar完成首次测量后会自动触发状态更新与重组,peekHeight会自动匹配AppBar的实际渲染高度,在不同屏幕密度、系统字体缩放、横竖屏切换场景下都能保证frontLayer恰好贴合在AppBar正下方,不需要硬编码固定dp值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 21:39:04