What is the proper way to center horizontally in B...
# compose
t
What is the proper way to center horizontally in BoxWithConstraints ?
c
Besides contentAlignment?
t
I'd like to only place one element. Trying to fix the bottom sheet to properly have maxwidth at 640dp but fail at properly centering it without wrapping to also handle the touch to dismiss.
I know wrapping is not really an issue in compose but trying to improve my lower level components knowledge.
c
I see. You can use the align modifier on a child in the Box to specifically place it different from contentAlignment
t
Hum CenterHorizontally does not work on Box? Or I'm missing something else.
Arf but BottomCenter works for this use case.
👍 1
Thanks I completely did not thought about BoxWithConstraint also having the BoxScope
👍 1
So for the record it does not seems to work after all, if the bottomsheet have different size when reshown the positioning is wrong I suspect the `val fullHeight = constraints.maxHeight.toFloat()`is not updated but lack time to investigate. The Row wrapping works until Material3 modal bottomsheet is created and hopefully support edge to edge status bar handling and maxwidth in landscape.
c
Code snippet?
t
Copy code
@Composable
fun ModalBottomSheetLayout(
    sheetContent: @Composable ColumnScope.() -> Unit,
    modifier: Modifier = Modifier,
    sheetState: ModalBottomSheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden),
    sheetShape: Shape = MaterialTheme.shapes.large,
    sheetElevation: Dp = ModalBottomSheetDefaults.Elevation,
    sheetBackgroundColor: Color = MaterialTheme.colorScheme.surface,
    sheetContentColor: Color = contentColorFor(sheetBackgroundColor),
    scrimColor: Color = ModalBottomSheetDefaults.scrimColor,
    content: @Composable () -> Unit
) {
    val scope = rememberCoroutineScope()
    BoxWithConstraints(modifier) {
        val fullHeight = constraints.maxHeight.toFloat()
        val sheetHeightState = remember { mutableStateOf<Float?>(null) }
        Box(Modifier.fillMaxSize()) {
            content()
            Scrim(
                color = scrimColor,
                onDismiss = {
                    if (sheetState.confirmStateChange(ModalBottomSheetValue.Hidden)) {
                        scope.launch { sheetState.hide() }
                    }
                },
                visible = sheetState.targetValue != ModalBottomSheetValue.Hidden
            )
        }
        Column(
            modifier = Modifier
                .widthIn(max = 640.dp)
                .fillMaxWidth()
                .align(BottomCenter)
                .nestedScroll(sheetState.nestedScrollConnection)
                .offset {
                    val y = if (sheetState.anchors.isEmpty()) {
                        // if we don't know our anchors yet, render the sheet as hidden
                        fullHeight.roundToInt()
                    } else {
                        // if we do know our anchors, respect them
                        sheetState.offset.value.roundToInt()
                    }
                    IntOffset(0, y)
                }
                .bottomSheetSwipeable(sheetState, fullHeight, sheetHeightState)
                .onGloballyPositioned {
                    sheetHeightState.value = it.size.height.toFloat()
                }
                .semantics {
                    if (sheetState.isVisible) {
                        dismiss {
                            if (sheetState.confirmStateChange(ModalBottomSheetValue.Hidden)) {
                                scope.launch { sheetState.hide() }
                            }
                            true
                        }
                        if (sheetState.currentValue == ModalBottomSheetValue.HalfExpanded) {
                            expand {
                                if (sheetState.confirmStateChange(ModalBottomSheetValue.Expanded)) {
                                    scope.launch { sheetState.expand() }
                                }
                                true
                            }
                        } else if (sheetState.hasHalfExpandedState) {
                            collapse {
                                if (sheetState.confirmStateChange(ModalBottomSheetValue.HalfExpanded)) {
                                    scope.launch { sheetState.halfExpand() }
                                }
                                true
                            }
                        }
                    }
                }
        ) {
            Spacer(modifier = Modifier.statusBarsPadding())
            Surface(
                modifier = Modifier.fillMaxWidth(),
                shape = sheetShape,
                tonalElevation = sheetElevation,
                color = sheetBackgroundColor,
                contentColor = sheetContentColor
            ) {
                Column(content = sheetContent)
            }
        }
    }
}
It's a small variation of the m2 bottomsheet to be M3 colors and limit 640dp and handle status bar.
That version does not properly place the content when the next content is smaller than the previous one.
Removing the .align and wrapping the column with `Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {`fix this