Issue
How can i programmatically set the peekHeight
of androidx.compose.material.BackdropScaffold
, so that the frontlayer
is exactly underneath the appBar
?
I have this code to build the app bar
@Composable
fun MyAppBar(backdropRevealed: Boolean, onBackdropReveal: (Boolean) -> Unit = {}) {
var size by remember { mutableStateOf(IntSize.Zero) }
SmallTopAppBar(
modifier = Modifier.onSizeChanged { size = it },
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 {
// Reveal to conceal
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"
)
}
}
)
}
and my variable size does contain the actual height
i cannot see how to pass this to my BackdropScaffold to set its peekHeight
heres the Backdrop code
val myAppBar: @Composable () -> Unit = {
MyAppBar(
backdropRevealed = backdropRevealed,
onBackdropReveal = {
if (!scaffoldState.isAnimationRunning) {
backdropRevealed = it
scope.launch {
if (scaffoldState.isConcealed) {
scaffoldState.reveal()
} else {
scaffoldState.conceal()
}
}
}
})
}
BackdropScaffold(
scaffoldState = scaffoldState,
gesturesEnabled = false,
appBar = myAppBar,
backLayerBackgroundColor = MaterialTheme.colorScheme.secondary,
backLayerContentColor = MaterialTheme.colorScheme.onSecondary,
backLayerContent = { ShowcaseBackLayerContent() },
frontLayerContent = { ShowcaseFrontLayerContent() },
frontLayerScrimColor = Color.Unspecified,
peekHeight = 70.dp
) {
}
how can i programmatically set peekHeight
to the size.height
?
Solution
Your code works when you get size from Modifier.onSizeChanged and pass it via a callback to your BackdropScaffold
@Composable
private fun MyComposable() {
val backdropScaffoldState =
rememberBackdropScaffoldState(initialValue = BackdropValue.Revealed)
var peekHeight by remember { mutableStateOf(BackdropScaffoldDefaults.PeekHeight) }
val density = LocalDensity.current
BackdropScaffold(
appBar = {
MyAppBar(true,
onSizeChanged = {
with(density) {
peekHeight = it.height.toDp()
}
},
onBackdropReveal = {
}
)
},
scaffoldState = backdropScaffoldState,
peekHeight = peekHeight,
backLayerContent = {
BackLayerContent()
},
frontLayerContent = {
FrontLayerContent()
}
) {
}
}
@Composable
fun FrontLayerContent() {
Column(modifier = Modifier.fillMaxSize()) {
Text("Back Layer", fontSize = 20.sp)
}
}
@Composable
fun BackLayerContent() {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text("Back Layer", fontSize = 40.sp, color = Color.White)
}
}
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun MyAppBar(
backdropRevealed: Boolean,
onSizeChanged: (IntSize) -> Unit,
onBackdropReveal: (Boolean) -> Unit = {}
) {
var size by remember { mutableStateOf(IntSize.Zero) }
SmallTopAppBar(
modifier = Modifier
.wrapContentHeight()
.onSizeChanged {
size = it
onSizeChanged(it)
println("🚀 SIZE: $size")
},
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 {
// Reveal to conceal
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 = { }) {
Icon(
imageVector = Icons.Rounded.MoreVert,
contentDescription = "Localized description"
)
}
}
)
}
Answered By - Thracian
Answer Checked By - Mildred Charles (JavaFixing Admin)