I'm using a bottom navigation bar with 5 items and I want that 3' icon in the middle is drawn over the top of the bottom navigation bar.
This is how my code looks like
@Composable
private fun BottomNavigationBar() {
var selectedItem by remember { mutableIntStateOf(0) }
NavigationBar(
modifier = Modifier
.fillMaxWidth()
.height(96.dp)
.padding(top = 26.dp)
.border(
width = 1.dp,
color = Color(0xFFE5E5E5),
),
containerColor = Color.White,
) {
navigationItems.forEachIndexed { index, item ->
if (item is NavigationItem.Guide) {
NavigationBarItem(
modifier = Modifier
.width(74.dp)
.height(82.dp)
.offset(y = (-20).dp),
selected = selectedItem == index,
onClick = { selectedItem = index },
icon = {
Image(
modifier = Modifier
.size(60.dp),
painter = painterResource(id = R.drawable.ic_nav_guide),
contentDescription = ""
)
},
label = { Text(text = item.title ?: "") }
)
} else {
NavigationBarItem(
selected = selectedItem == index,
onClick = { selectedItem = index },
icon = {
Icon(
painter = painterResource(id = item.icon ?: 0),
contentDescription = "Nav Icon"
)
},
label = { Text(text = item.title ?: "") }
)
}
}
}
}
and this his how it actualy looks like.
How can I fix the clipping of the image, so that one half is displayed over and the other half inside the nav bar?
You will have to create your own MyNavigationBar
Composable and use the clip
Modifier to cut the Shape from the NavigationBar
.
You can use the following shape class:
private val HALF_CIRCLE_RADIUS_DP = 32.dp // specify radius of circle in dp here
class BottomCurve : Shape {
override fun createOutline(
size: Size,
layoutDirection: LayoutDirection,
density: Density
): Outline {
// convert to px
val halfCircleRadius = with(density) { HALF_CIRCLE_RADIUS_DP.toPx() }
return Outline.Generic(path = Path().apply {
val halfCircleCenterX = size.width / 2
val halfCircleCenterY = halfCircleRadius.toFloat()
// Move to the center of the half-circle and start drawing the semicircle
moveTo(halfCircleCenterX, halfCircleCenterY)
// Draw the half circle on the top line of the rectangle
arcTo(
rect = Rect(
left = halfCircleCenterX - halfCircleRadius,
top = 0f,
right = halfCircleCenterX + halfCircleRadius,
bottom = (halfCircleRadius * 2).toFloat()
),
startAngleDegrees = 180f,
sweepAngleDegrees = 180f,
forceMoveTo = true
)
lineTo(size.width, halfCircleRadius.toFloat())
lineTo(size.width, size.height)
lineTo(0f, size.height)
lineTo(0f, halfCircleRadius.toFloat())
})
}
}
Then, create your MyNavigationBar
Composable:
@Composable
fun MyNavigationBar(
modifier: Modifier = Modifier,
containerColor: Color = NavigationBarDefaults.containerColor,
contentColor: Color = MaterialTheme.colorScheme.contentColorFor(containerColor),
tonalElevation: Dp = NavigationBarDefaults.Elevation,
windowInsets: WindowInsets = NavigationBarDefaults.windowInsets,
content: @Composable RowScope.() -> Unit
) {
Surface(
color = containerColor,
contentColor = contentColor,
tonalElevation = tonalElevation,
modifier = modifier
.height(118.dp)
.clip(BottomCurve())
) {
Row(
modifier = Modifier
.fillMaxSize()
.windowInsetsPadding(windowInsets)
.selectableGroup(),
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.Bottom,
content = content
)
}
}
Finally, invoke it as follows:
var selectedItem by remember { mutableIntStateOf(0) }
MyNavigationBar(
containerColor = Color.White,
) {
//..
}
The output looks as follows:
You can adjust the Path or modify the offset
as per your needs.