Search code examples
androidandroid-jetpack-composeborderandroid-jetpack

Jetpack Compose - Custom Hexagon Border Curved Edge


I need to create Hexagon Shaped Border for ImageView but I'm unable to achieve it, following is the way I have tried:

HexagonShape:

class HexagonShape : Shape {

    override fun createOutline(
        size: Size,
        layoutDirection: LayoutDirection,
        density: Density
    ): Outline {
        return Outline.Generic(
            path = drawCustomHexagonPath(size)
        )
    }
}

fun drawCustomHexagonPath(size: Size): Path {
    return Path().apply {
        val radius = min(size.width / 2f, size.height / 2f)
        customHexagon(radius, size)
    }
}

fun Path.customHexagon(radius: Float, size: Size) {
    val triangleHeight = (sqrt(3.0) * radius / 2)
    val centerX = size.width / 2
    val centerY = size.height / 2

    moveTo(centerX, centerY + radius)
    lineTo((centerX - triangleHeight).toFloat(), centerY + radius/2)
    lineTo((centerX - triangleHeight).toFloat(), centerY - radius/2)
    lineTo(centerX, centerY - radius)
    lineTo((centerX + triangleHeight).toFloat(), centerY - radius/2)
    lineTo((centerX + triangleHeight).toFloat(), centerY + radius/2)

    close()
}

Calling from following Composable function:

@Composable
fun HexagonImg() {
    val myShape = HexagonShape()
    Image(
        painter = painterResource(id = R.drawable.ic_launcher_foreground),
        contentDescription = "My Hexagon Image",
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .wrapContentSize()
            .graphicsLayer {
                shadowElevation = 8.dp.toPx()
                shape = myShape
                clip = true
            }
            .background(color = Color.Cyan)
            .drawBehind {
                drawPath(
                    path = drawCustomHexagonPath(size),
                    color = Color.Red,
                    style = Stroke(
                        width = 10.dp.toPx(),
                        pathEffect = PathEffect.cornerPathEffect(40f)
                    )
                )
            }
    )
}

The output is coming as below: Current Output

My Expected Output is Curved Hexagon Border on both inner and outer side of Border like below:

Expected Output

Can someone help me in figuring out what have I missed/done wrong?


Solution

  • It happens since your image is clipped and the path is drawn inside the bounds of the image.

    You can do something different:

    Box(modifier = Modifier
        .padding(10.dp)
        .drawWithContent {
            drawContent()
            drawPath(
                path = drawCustomHexagonPath(size),
                color = Color.Red,
                style = Stroke(
                    width = 10.dp.toPx(),
                    pathEffect = PathEffect.cornerPathEffect(40f)
                )
            )
        }
        .wrapContentSize()
    ){
        Image(
            painter = painterResource(id = R.drawable.ic_launcher_foreground),
            contentDescription = "My Hexagon Image",
            contentScale = ContentScale.Crop,
            modifier = Modifier
                .wrapContentSize()
                .graphicsLayer {
                    shadowElevation = 8.dp.toPx()
                    shape = myShape
                    clip = true
                }
                .background(color = Color.Cyan)
        )
    }
    

    enter image description here