How can I create custom oval shape in Jetpack Compose

In Jetpack Compose how can I create custom oval shape?

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:left="-150dp"
        android:right="-150dp"
        android:top="-200dp">
        <shape android:shape="oval">
            <solid android:color="?attr/colorPrimary" />
        </shape>
    </item>
</layer-list>

Oval shape

>Solution :

You can use Canvas for it:

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.drawscope.DrawScope

@Composable
fun CustomOvalBottomShape() {
    Canvas(
        modifier = Modifier.fillMaxSize()
    ) {
        drawPath(
            path = createOvalBottomPath(),
            brush = Brush.linearGradient(
                colors = listOf(Color.Green, Color.Yellow),
                start = Offset(0f, size.height),
                end = Offset(size.width, size.height / 2)
            )
        )
    }
}

private fun DrawScope.createOvalBottomPath(): Path {
    val path = Path()
    path.moveTo(0f, 0f) // Top-left corner
    path.lineTo(size.width, 0f) // Top-right corner
    path.lineTo(size.width, size.height - size.width / 2) // Bottom-right corner (before oval)
    path.quadraticBezierTo(size.width / 2, size.height, 0f, size.height - size.width / 2) // Oval bottom-left
    path.close()
    return path
}

OR

If you want to make it easier and if you know how much rounded value it should have, you can use Box() with custom RoundedCorners shape


@Composable
fun CustomOvalBottomShape() {
    Box(
        modifier = Modifier.fillMaxSize().background(Color.Black)
    ) {
        Box(
            modifier = Modifier
                .fillMaxSize(0.8f)
                .padding(8.dp)
                .clip(RoundedCornerShape(bottomStart = 100.dp, bottomEnd = 100.dp))
                .background(color = Color.Blue)
        )
    }
}

Leave a Reply