Skip to content

Instantly share code, notes, and snippets.

@iprashantpanwar
Last active September 16, 2025 20:28
Show Gist options
  • Select an option

  • Save iprashantpanwar/bb99565b52e4d7fefbb84c9d3720f944 to your computer and use it in GitHub Desktop.

Select an option

Save iprashantpanwar/bb99565b52e4d7fefbb84c9d3720f944 to your computer and use it in GitHub Desktop.
Draw a Ticket Shape in Jetpack Compose
@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()
}
}
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