Reputation: 567
I had a question about making this view in Compose and I have no idea about implementing it.
My current code looks like this:
Box(
modifier = Modifier
.fillMaxSize()
.height(300.dp)
) {
Canvas(modifier = Modifier.matchParentSize()) {
drawRoundRect(
color = Color.Yellow,
cornerRadius = CornerRadius(16.dp.toPx(), 16.dp.toPx())
)
drawRoundRect(
color = Color.White,
topLeft = Offset(
x = size.width / 5,
y = size.height - 60.dp.toPx()
),
size = Size((size.width / 5) * 3, 50.dp.toPx() * 2),
cornerRadius = CornerRadius(24.dp.toPx(), 24.dp.toPx()),
)
}
Box(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
Text(
text = "Test",
modifier = Modifier.align(Alignment.BottomCenter)
)
}
}
Result is the following:
Upvotes: 4
Views: 3775
Reputation: 142
Also you can use a custom Shape for your Composables to give them a specific outline. Just extend the Shape interface and override the createOutline() method.
Example:
For the corners, the Path API offers a function arcTo(). Then, to draw the edges of the shape, use the lineTo() method.
class RoundedRectOutlinedCorner(
private val cornerRadius: Dp = 16.dp,
private val cutOutHeight: Dp = 60.dp,
private val cutOutWidth: Dp = 145.dp
) : Shape {
override fun createOutline(
size: Size, layoutDirection: LayoutDirection, density: Density
): Outline {
return Outline.Generic(Path().apply {
val cornerRadius = with(density) { cornerRadius.toPx() }
val cutOutHeight = with(density) { cutOutHeight.toPx() }
val cutOutWidth = with(density) { cutOutWidth.toPx() }
arcTo(
rect = Rect(offset = Offset(0f, 0f), Size(cornerRadius, cornerRadius)),
startAngleDegrees = 180f,
sweepAngleDegrees = 90f,
forceMoveTo = false
)
lineTo(size.width - cutOutWidth - cornerRadius, 0f)
arcTo(
rect = Rect(
offset = Offset(size.width - cutOutWidth - cornerRadius, 0f),
Size(cornerRadius, cornerRadius)
), startAngleDegrees = 270.0f, sweepAngleDegrees = 90f, forceMoveTo = false
)
lineTo(size.width - cutOutWidth, cutOutHeight - cornerRadius)
arcTo(
rect = Rect(
offset = Offset(size.width - cutOutWidth, cutOutHeight - cornerRadius),
Size(cornerRadius, cornerRadius)
), startAngleDegrees = 180.0f, sweepAngleDegrees = -90f, forceMoveTo = false
)
lineTo(size.width - cornerRadius, cutOutHeight)
arcTo(
rect = Rect(
offset = Offset(size.width - cornerRadius, cutOutHeight),
Size(cornerRadius, cornerRadius)
), startAngleDegrees = 270f, sweepAngleDegrees = 90f, forceMoveTo = false
)
lineTo(size.width, size.height - cornerRadius)
arcTo(
rect = Rect(
offset = Offset(size.width - cornerRadius, size.height - cornerRadius),
Size(cornerRadius, cornerRadius)
), startAngleDegrees = 0f, sweepAngleDegrees = 90f, forceMoveTo = false
)
lineTo(cornerRadius, size.height)
arcTo(
rect = Rect(
offset = Offset(0f, size.height - cornerRadius),
Size(cornerRadius, cornerRadius)
), startAngleDegrees = 90f, sweepAngleDegrees = 90f, forceMoveTo = false
)
close()
})
}
}
Usage: Then, you can clip a shape with:
Modifier
.height(250.dp)
.clip(RoundedRectOutlinedCorner()),
Or with .graphicsLayer/.background etc.
Result:
Upvotes: 0
Reputation: 88142
To clip some path from an other path, you can use clipPath
.
And to outer corner radius, you need to add arcs to the path manually, like this:
Canvas(modifier = Modifier.matchParentSize()) {
val outerCornerRadius = 16.dp.toPx()
val clippedPath = Path().apply {
val innerCornerRadius = 24.dp.toPx()
val rectSize = Size(round((size.width / 5) * 3), round(50.dp.toPx() * 2))
val rect = Rect(
offset = Offset(
x = (size.width - rectSize.width) / 2,
y = size.height - rectSize.height
),
size = rectSize
)
addRoundRect(
RoundRect(
rect,
topLeft = CornerRadius(x = innerCornerRadius, y = innerCornerRadius),
topRight = CornerRadius(x = innerCornerRadius, y = innerCornerRadius),
)
)
val outerCornerDiameter = outerCornerRadius * 2
val cornerSize = Size(outerCornerDiameter,outerCornerDiameter)
val cornerOffset = Offset(outerCornerDiameter, outerCornerDiameter)
val cornerYOffset = Offset(0f, outerCornerDiameter)
moveTo(rect.bottomLeft - cornerYOffset)
addArc(
Rect(
offset = rect.bottomLeft - cornerOffset,
size = cornerSize
),
startAngleDegrees = 0f,
sweepAngleDegrees = 90f,
)
lineTo(rect.bottomLeft)
moveTo(rect.bottomRight - cornerYOffset)
addArc(
Rect(
offset = rect.bottomRight - cornerYOffset,
size = cornerSize
),
startAngleDegrees = 180f,
sweepAngleDegrees = -90f,
)
lineTo(rect.bottomRight)
}
clipPath(clippedPath, clipOp = ClipOp.Difference) {
drawRoundRect(
color = Color.Yellow,
cornerRadius = CornerRadius(outerCornerRadius, outerCornerRadius)
)
}
}
Result:
Upvotes: 8