1

enter image description here

I tried using Path and bezier curves concept using cubicTo() method.

I need height 70dp and width 333dp.

 @Composable
fun CurveShape() {
    val path = remember { Path() }

    Canvas(
        modifier = Modifier
            .height(80.dp)
            .fillMaxWidth()
            .background(Color.White)

            //.size(666.dp, 80.dp)
    ) {
        path.reset()
       
        path.cubicTo(x1 = 400f, y1 = 150f, x2 = 500f, y2 = 400f, x3 = size.width, y3 = 00.0f)
   
        drawPath(
            color = Color.Black,
            path = path,
        )
    }
}

This is giving me the output like below:

enter image description here

It is not giving me a propers shape. Corner shape are not properly shaped.

Please help to achieve this shape in jetpack compose.

Yogesh Nikam Patil
  • 1,192
  • 13
  • 18

2 Answers2

2

I think using two bazier curves would give you the dezired result:

Spacer(modifier = Modifier
            .height(80.dp)
            .width(333.dp)
            .background(Color.White)
            .drawWithCache {
                onDrawBehind {
                    val path = Path()
                    path.moveTo(0f, 0f)
                    path.cubicTo(x1 = 333.dp.toPx()/10, y1 = 0f, x2 = 333.dp.toPx()/4, y2 = 70.dp.toPx(), x3 = 333.dp.toPx()/2, y3 = 70.dp.toPx())
                    path.cubicTo(x1 = 333.dp.toPx()*3/4, y1 = 70.dp.toPx(), x2 = 333.dp.toPx()-333.dp.toPx()/10, y2 = 0f, x3 = 333.dp.toPx(), y3 = 0f)
                    drawPath(
                        path = path,
                        color = Color.Black,
                        style = Fill
                    )
                }
            })

correspoding image

With moveTo() function we assign the starting point of the bezier curve. The destination points are determined by (x3,y3) coordinates.
(x1,y1) act as anchor points for the start of the curve and (x2,y2) act as anchor points for destination of the curve.

For more details on how these anchor points affect the curve checkout this answer.

Mr. Techie
  • 622
  • 7
  • 17
2

Solution still using Canvas(..)

You will need to extend the Path out with a secondary path.cubicTo(..) call.

Here's a quick and dirty function I've written to generate these cubic curves based on bottomLeft and TopRight values of the curve in the canvas

@Composable
fun CurveShape() {
    Canvas(
        modifier = Modifier
            .height(80.dp)
            .fillMaxWidth()
            .background(Color.White)
    ) {
        drawCubicCurve(
            bottomLeft = Offset(0f, size.height),
            topRight = Offset(size.width, 0f),
            color = Color.Black
        )
    }
}

fun DrawScope.drawCubicCurve(
    bottomLeft: Offset,
    topRight: Offset,
    color: Color = Color.White
) {
    val x1Modifier = 0.41f
    val x2Modifier = 0.22f
    val x3Modifier = 0.5f
    val y1Modifier = 0f
    val y2Modifier = 1f
    val y3Modifier = 1f

    val delta = topRight.minus(bottomLeft)
    val width = delta.x
    val height = delta.y

    val path = Path()
    path.moveTo(bottomLeft.x, bottomLeft.y)
    path.cubicTo(
        x1 = bottomLeft.x.plus(width.times(x1Modifier)),
        y1 = bottomLeft.y.plus(height.times(y1Modifier)),
        x2 = bottomLeft.x.plus(width.times(x2Modifier)),
        y2 = topRight.y.times(y2Modifier),
        x3 = bottomLeft.x.plus(width.times(x3Modifier)),
        y3 = topRight.y.times(y3Modifier),
    )
    path.cubicTo(
        x1 = topRight.x.minus(width.times(x2Modifier)),
        y1 = topRight.y.times(y2Modifier),
        x2 = topRight.x.minus(width.times(x1Modifier)),
        y2 = bottomLeft.y.plus(height.times(y1Modifier)),
        x3 = topRight.x,
        y3 = bottomLeft.y,
    )
    drawPath(
        path = path,
        alpha = 0.5f,
        brush = Brush.verticalGradient(
            colors = listOf(
                color.copy(alpha = 0.0f),
                color.copy(alpha = 0.7f),
                color
            ), startY = bottomLeft.y, endY = topRight.y
        )
    )
    drawPath(
        color = color,
        path = path,
    )
}

Curve

My code draws the curve the other way around as you want it, so I encourage you to play around with the values here to get the resulting curve you want :)

Additionally calling .reset() is only required because you have remembered the Path(..). I'd advise you to not remember the Path() as you want to recalculate it whenever a recomposition occurs as the measurements of the Canvas may have changed. Resulting in a different path

ElliotSknr
  • 246
  • 1
  • 7