如何编程设置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
相关产品推荐
相关产品推荐

