Search code examples
kotlinandroid-studioandroid-jetpack-composeshapesoval

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)
            )
        }
    }