vanshg
03/05/2024, 11:02 PM/**
* Returns a [PathEffect] that draws a dashed line around the corners of a rounded rectangle
*
* @param cornerRadius The radius of the rounded corners
* @param roundedRectSize The size of the rounded rectangle
* @param extendCornerBy The amount to extend the corner dashes by. This will be distributed evenly
* on both ends of each corner
*/
fun roundedRectCornerDashPathEffect(
cornerRadius: Float,
roundedRectSize: Size,
extendCornerBy: Float = 0f,
): PathEffect {
// Each corner's length is a quarter circle
val cornerLength = (2 * Math.PI * cornerRadius / 4f).toFloat() + extendCornerBy
// There are 2 corners, so we subtract 2 * radius from the width (same goes for height)
val cornerHeight = cornerRadius + (extendCornerBy / 2)
val roundedRectWidthExcludingCorners = roundedRectSize.width - (2 * cornerHeight)
val roundedRectHeightExcludingCorners = roundedRectSize.height - (2 * cornerHeight)
return dashPathEffect(
intervals = floatArrayOf(
cornerLength,
roundedRectWidthExcludingCorners,
cornerLength,
roundedRectHeightExcludingCorners,
cornerLength,
roundedRectWidthExcludingCorners,
cornerLength,
roundedRectHeightExcludingCorners,
),
phase = cornerLength - (extendCornerBy / 2),
)
}
I use this within a Canvas like so:
// Draw the rounded rectangle cutout
drawRoundRect(
cornerRadius = CornerRadius(radius),
size = roundedRectSize,
topLeft = roundedRectTopLeft,
color = Color.Black.copy(alpha = cutoutOpacity),
style = Fill,
blendMode = BlendMode.SrcIn,
)
// Draw the corner borders
drawRoundRect(
cornerRadius = CornerRadius(radius),
size = roundedRectSize,
topLeft = roundedRectTopLeft,
color = cornerBorderColor,
style = Stroke(
width = 4.dp.toPx(),
cap = StrokeCap.Round,
pathEffect = roundedRectCornerDashPathEffect(
cornerRadius = radius,
roundedRectSize = roundedRectSize,
extendCornerBy = 16.dp.toPx(),
),
),
)
The same code results in the first image on the emulator and Compose preview, but works on a real device. If I modify the order of intervals
in the dashPathEffect, then it looks okay in Compose Preview and on an emulator, but fails similarly on a real device. Where does this indeterminism come from? I assume it is related to something about Path/Canvasromainguy
03/05/2024, 11:04 PMvanshg
03/05/2024, 11:04 PMromainguy
03/05/2024, 11:06 PMromainguy
03/05/2024, 11:08 PMvanshg
03/05/2024, 11:13 PMvanshg
03/05/2024, 11:14 PMromainguy
03/05/2024, 11:18 PMromainguy
03/05/2024, 11:19 PMromainguy
03/05/2024, 11:19 PMvanshg
03/05/2024, 11:21 PMromainguy
03/05/2024, 11:22 PMvanshg
03/05/2024, 11:23 PMval radius = 16.dp.toPx()
would not be enough?romainguy
03/05/2024, 11:28 PMvanshg
03/05/2024, 11:30 PMvanshg
03/05/2024, 11:31 PMval roundedRect = RoundRect(
rect = Rect(offset = roundedRectTopLeft, size = roundedRectSize),
cornerRadius = CornerRadius(radius),
)
drawPath(
path = Path().apply {
addRoundRect(roundedRect)
},
color = cornerBorderColor,
style = Stroke(
width = 4.dp.toPx(),
cap = StrokeCap.Round,
pathEffect = roundedRectCornerDashPathEffect(
cornerRadius = radius,
roundedRectSize = roundedRectSize,
extendCornerBy = 16.dp.toPx(),
),
),
)
vanshg
03/05/2024, 11:32 PMvanshg
03/05/2024, 11:37 PM