The post by @Thracian made me investigate their code, and then combined it with the code for CutCornerShape
and RoundedCornerShape
.
Here's the SemiRoundCutCornerShape
fun SemiRoundCutCornerShape(size: Dp, roundedLeft: Boolean = true) = SemiRoundCutCornerShape(size, size, roundedLeft)
fun SemiRoundCutCornerShape(cutSize: Dp, roundSize: Dp, roundedLeft: Boolean = true) = SemiRoundCutCornerShape(
topStart = CornerSize(roundSize),
topEnd = CornerSize(cutSize),
bottomEnd = CornerSize(roundSize),
bottomStart = CornerSize(cutSize),
roundedLeft = roundedLeft
)
class SemiRoundCutCornerShape(
topStart: CornerSize,
topEnd: CornerSize,
bottomEnd: CornerSize,
bottomStart: CornerSize,
private val roundedLeft: Boolean = true
) : CornerBasedShape(
topStart = topStart,
topEnd = topEnd,
bottomEnd = bottomEnd,
bottomStart = bottomStart,
) {
override fun createOutline(
size: Size,
topStart: Float,
topEnd: Float,
bottomEnd: Float,
bottomStart: Float,
layoutDirection: LayoutDirection
): Outline {
val roundOutline: Outline = Outline.Rounded(
when (layoutDirection == LayoutDirection.Ltr && roundedLeft) {
true -> RoundRect(
rect = size.toRect(),
topLeft = CornerRadius(if (layoutDirection == LayoutDirection.Ltr) topStart else topEnd),
bottomRight = CornerRadius(if (layoutDirection == LayoutDirection.Ltr) bottomEnd else bottomStart),
)
false -> RoundRect(
rect = size.toRect(),
topRight = CornerRadius(if (layoutDirection == LayoutDirection.Ltr) topEnd else topStart),
bottomLeft = CornerRadius(if (layoutDirection == LayoutDirection.Ltr) bottomStart else bottomEnd)
)
}
)
val cutOutline: Outline = Outline.Generic(
when (layoutDirection == LayoutDirection.Ltr && roundedLeft) {
true -> Path().apply {
var cornerSize = 0F
moveTo(0f, cornerSize)
lineTo(cornerSize, 0f)
cornerSize = topEnd
lineTo(size.width - cornerSize, 0f)
lineTo(size.width, cornerSize)
cornerSize = 0F
lineTo(size.width, size.height - cornerSize)
lineTo(size.width - cornerSize, size.height)
cornerSize = bottomStart
lineTo(cornerSize, size.height)
lineTo(0f, size.height - cornerSize)
close()
}
false -> Path().apply {
var cornerSize = topEnd
moveTo(0f, cornerSize)
lineTo(cornerSize, 0f)
cornerSize = 0F
lineTo(size.width - cornerSize, 0f)
lineTo(size.width, cornerSize)
cornerSize = bottomStart
lineTo(size.width, size.height - cornerSize)
lineTo(size.width - cornerSize, size.height)
cornerSize = 0F
lineTo(cornerSize, size.height)
lineTo(0f, size.height - cornerSize)
close()
}
}
)
return Outline.Generic(Path.combine(
operation = PathOperation.Intersect,
path1 = Path().apply { addOutline(cutOutline) },
path2 = Path().apply { addOutline(roundOutline) }
))
}
override fun copy(
topStart: CornerSize,
topEnd: CornerSize,
bottomEnd: CornerSize,
bottomStart: CornerSize
): CornerBasedShape = SemiRoundCutCornerShape(
topStart = topStart,
topEnd = topEnd,
bottomEnd = bottomEnd,
bottomStart = bottomStart
)
override fun toString(): String {
return "SemiRoundCutShape(topStart = $topStart, topEnd = $topEnd, bottomEnd = " +
"$bottomEnd, bottomStart = $bottomStart)"
}
}
Here used to create
SemiRoundCutCornerShape(8.dp)
SemiRoundCutCornerShape(24.dp, roundedLeft = false)
SemiRoundCutCornerShape(16.dp)
SemiRoundCutCornerShape(
topStart = CornerSize(60.dp),
topEnd = CornerSize(8.dp),
bottomEnd = CornerSize(16.dp),
bottomStart = CornerSize(20.dp)
)