Last active
September 16, 2025 20:28
-
-
Save iprashantpanwar/bb99565b52e4d7fefbb84c9d3720f944 to your computer and use it in GitHub Desktop.
Draw a Ticket Shape in Jetpack Compose
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @Composable | |
| fun TicketView() { | |
| Box( | |
| modifier = Modifier | |
| .size(400.dp) | |
| .padding(horizontal = 16.dp) | |
| .background( | |
| color = Color.White, | |
| shape = TicketShapeVertically(cornerRadius = 12.dp, cutoutRadius = 8.dp) | |
| ) | |
| ) { | |
| // ticket stuff | |
| } | |
| } | |
| @Preview | |
| @Composable | |
| fun TicketViewPreview() { | |
| MaterialTheme { | |
| TicketView() | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import androidx.compose.ui.geometry.CornerRadius | |
| import androidx.compose.ui.geometry.Rect | |
| import androidx.compose.ui.geometry.RoundRect | |
| import androidx.compose.ui.graphics.Outline | |
| import androidx.compose.ui.graphics.Path | |
| import androidx.compose.ui.graphics.PathOperation | |
| import androidx.compose.ui.graphics.Shape | |
| import androidx.compose.ui.unit.Density | |
| import androidx.compose.ui.unit.Dp | |
| import androidx.compose.ui.unit.LayoutDirection | |
| import androidx.compose.ui.unit.dp | |
| class TicketShapeVertically( | |
| private val cornerRadius: Dp = 16.dp, | |
| private val cutoutRadius: Dp = 16.dp, | |
| /** | |
| * Fraction of the height where the cutout center will be placed. | |
| * Example: 0.5f = middle, 0.25f = upper quarter. | |
| */ | |
| private val cutoutHeightFraction: Float = 0.80f | |
| ) : Shape { | |
| override fun createOutline( | |
| size: androidx.compose.ui.geometry.Size, | |
| layoutDirection: LayoutDirection, | |
| density: Density | |
| ): Outline { | |
| with(density) { | |
| val cornerRadiusPx = cornerRadius.toPx() | |
| val cutoutRadiusPx = cutoutRadius.toPx() | |
| // Base ticket rectangle with rounded corners | |
| val ticketPath = Path().apply { | |
| addRoundRect( | |
| RoundRect( | |
| rect = Rect(0f, 0f, size.width, size.height), | |
| cornerRadius = CornerRadius(cornerRadiusPx, cornerRadiusPx) | |
| ) | |
| ) | |
| } | |
| // Calculate vertical center for cutouts | |
| val cutoutCenterY = size.height * cutoutHeightFraction | |
| // Cutout on the left edge | |
| val leftCutout = Path().apply { | |
| addOval( | |
| Rect( | |
| left = -cutoutRadiusPx, | |
| top = cutoutCenterY - cutoutRadiusPx, | |
| right = cutoutRadiusPx, | |
| bottom = cutoutCenterY + cutoutRadiusPx | |
| ) | |
| ) | |
| } | |
| // Cutout on the right edge | |
| val rightCutout = Path().apply { | |
| addOval( | |
| Rect( | |
| left = size.width - cutoutRadiusPx, | |
| top = cutoutCenterY - cutoutRadiusPx, | |
| right = size.width + cutoutRadiusPx, | |
| bottom = cutoutCenterY + cutoutRadiusPx | |
| ) | |
| ) | |
| } | |
| // Subtract cutouts from base shape | |
| val finalPath = Path().apply { | |
| op(ticketPath, leftCutout, PathOperation.Difference) | |
| op(this, rightCutout, PathOperation.Difference) | |
| } | |
| return Outline.Generic(finalPath) | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment