Reputation: 87615
I'd need to replicate android XML view from this answer but in Jetpack Compose with pure kotlin
Upvotes: 29
Views: 20766
Reputation: 2946
To create a dotted line in compose, you need to set the line's cap
to StrokeCap.Round
and set the dash width (first value in the intervals
array) to 0f
.
Take note that setting the dash width to 0f
while leaving the line's cap
set to the default, which is StrokeCap.Butt
, will make the line invisible.
@Preview
@Composable
private fun DottedLinePreview() {
Canvas(
modifier = Modifier
.size(200.dp)
.background(Color.White)
) {
drawLine(
color = Color.Black,
start = Offset(10.dp.toPx(), 100.dp.toPx()),
end = Offset(190.dp.toPx(), 100.dp.toPx()),
strokeWidth = 5.dp.toPx(),
cap = StrokeCap.Round, // important!
pathEffect = PathEffect.dashPathEffect(
intervals = floatArrayOf(
0f, // important!
8.dp.toPx(), // must be greater than stroke width
),
),
)
}
}
Upvotes: 1
Reputation: 192
Use the below composable wherever you want to put a dashed divider. I just made this function from Gabriele Mariotti's answer
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.PathEffect
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
@Preview
@Composable
private fun DashedDividerPreview() {
DashedDivider(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp)
)
}
@Composable
fun DashedDivider(
modifier: Modifier = Modifier,
dashWidth: Dp = 4.dp,
dashHeight: Dp = 2.dp,
gapWidth: Dp = 2.dp,
color: Color = Color.Gray,
) {
Canvas(modifier) {
val pathEffect = PathEffect.dashPathEffect(
intervals = floatArrayOf(dashWidth.toPx(), gapWidth.toPx()),
phase = 0f
)
drawLine(
color = color,
start = Offset(0f, 0f),
end = Offset(size.width, 0f),
pathEffect = pathEffect,
strokeWidth = dashHeight.toPx()
)
}
}
Upvotes: 7
Reputation: 363469
You can simply use a Canvas
with the method drawLine
applying as pathEffect
a PathEffect.dashPathEffect
:
val pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 0f)
Canvas(Modifier.fillMaxWidth().height(1.dp)) {
drawLine(
color = Color.Red,
start = Offset(0f, 0f),
end = Offset(size.width, 0f),
pathEffect = pathEffect
)
}
You can also apply the same pathEffect to other method as:
val stroke = Stroke(width = 2f,
pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 0f)
)
Canvas(Modifier.fillMaxWidth().height(70.dp)){
drawRoundRect(color = Color.Red,style = stroke)
}
Upvotes: 70
Reputation: 87615
You can create a shape in Jetpack Compose like this:
private data class DottedShape(
val step: Dp,
) : Shape {
override fun createOutline(
size: Size,
layoutDirection: LayoutDirection,
density: Density
) = Outline.Generic(Path().apply {
val stepPx = with(density) { step.toPx() }
val stepsCount = (size.width / stepPx).roundToInt()
val actualStep = size.width / stepsCount
val dotSize = Size(width = actualStep / 2, height = size.height)
for (i in 0 until stepsCount) {
addRect(
Rect(
offset = Offset(x = i * actualStep, y = 0f),
size = dotSize
)
)
}
close()
})
}
Usage:
Box(
Modifier
.height(1.dp)
.fillMaxWidth()
.background(Color.Gray, shape = DottedShape(step = 10.dp))
)
Result:
Upvotes: 36