Anyone knows how I can arrange the two inner Botto...
# compose
a
Anyone knows how I can arrange the two inner BottomNav Items so that they are not so close to the “+” FAB? I tried surrounding the forEach which displays the Items with a Row and use the Arrangement modifier like so:
Copy code
Row(horizontalArrangement = Arrangement.SpaceBetween) { //Not working :(
items.forEach { item ->
    BottomNavigationItem(
        icon = { Icon(painterResource(id = item.icon), contentDescription = item.title) },
        label = { Text(text = item.title) },
        selectedContentColor = Color.White,
        unselectedContentColor = Color.White.copy(0.4f),
        alwaysShowLabel = true,
        selected = currentRoute == item.route,
        onClick = {
            navController.navigate(item.route) { 
                navController.graph.startDestinationRoute?.let { route ->
                    popUpTo(route) {
                        saveState = true
                    }
                } 
                launchSingleTop = true 
                restoreState = true
            }
        }
    )
}

}
😯 1
Fixed it by adding a Spacer with the weight of 1f at the third position:
Copy code
items.forEachIndexed { i, item ->
    if (i == items.count() / 2) {
        Spacer(Modifier.weight(1f))
    }
    BottomNavigationItem(
        // ...
👍 1
m
How did you create that round empty inset around the fab in the bottom bar? it's so nice!
a
@Mehdi Haghgoo feel free to use this code if you don’t want to be bound to material design:
Copy code
class CutoutShape(
    private val radius: Dp,
    private val center: Dp,
) : Shape {
    override fun createOutline(
        size: Size,
        layoutDirection: LayoutDirection,
        density: Density
    ): Outline = with(density) {
        val boundingPath = Path().apply {
            addRoundRect(RoundRect(size.toRect(), CornerRadius(radius.toPx())))
        }

        val path = Path().apply {
            addCutoutShape(size, density)
            op(boundingPath, this, PathOperation.Difference)
        }
        return Outline.Generic(path)
    }

    private fun Path.addCutoutShape(size: Size, density: Density) {
        with(density) {
            val fabMargin = 9.dp.toPx()
            val fabDiameter = 60.dp.toPx()
            val cradleDiameter = (fabMargin * 2F) + fabDiameter
            val cradleRadius = cradleDiameter / 2F

            val middle = center.toPx()

            val cornerSize = 18.dp.toPx()

            val distanceBetweenCenters = cradleRadius + cornerSize
            val distanceBetweenCentersSquared = distanceBetweenCenters * distanceBetweenCenters

            val distanceY: Float = cornerSize
            val distanceX = sqrt(distanceBetweenCentersSquared - distanceY * distanceY)

            val leftRoundedCornerCircleX = middle - distanceX
            val rightRoundedCornerCircleX = middle + distanceX


            val cornerRadiusArcLength = Math.toDegrees(atan(distanceX / distanceY).toDouble()).toFloat()
            val cutoutArcOffset = (90F - cornerRadiusArcLength) + 1.75F


            lineTo(leftRoundedCornerCircleX, 0F)

            arcTo(
                Rect(
                    leftRoundedCornerCircleX - cornerSize,
                    0F,
                    leftRoundedCornerCircleX + cornerSize,
                    cornerSize * 2F
                ),
                270F,
                cornerRadiusArcLength,
                false,
            )

            arcTo(
                Rect(
                    middle - cradleRadius,
                    -cradleRadius,
                    middle + cradleRadius,
                    cradleRadius,
                ),
                180F - cutoutArcOffset,
                cutoutArcOffset * 2 - 180F,
                false
            )

            arcTo(
                Rect(
                    rightRoundedCornerCircleX - cornerSize,
                    0F,
                    rightRoundedCornerCircleX + cornerSize,
                    cornerSize * 2
                ),
                270F - cornerRadiusArcLength,
                cornerRadiusArcLength,
                false,
            )

            lineTo(rightRoundedCornerCircleX, 0F)

            close()
        }
    }
}
m
Wow. Thank you @andrew. Do you mean Material Compose does not support such cutout shape?
a
It does, but if you wanted it manually without utilizing the BottomAppBar and Scaffold
I personally wasn't using material components here
In this case, it's a custom bottombar component with that as it's background
You could slot in your own from wherever, and just use that as the background and shadow clip
1
m
I didn't find any sample on Android Docs showing how to create cutout shapes in Compose. Now, I see your code. Thank you
a
This would be handled automatically by the toolbar
1
And Scaffold
1