Как нарисовать границу вокруг элементов LazyColumn в Android Compose

Естьitems() {}секции внутриLazyColumn. Поэтому я хотел бы нарисовать границу с закругленными углами вокруг каждой секции. Есть ли какой-нибудь метод?

      // need to draw a border around the items
LazyColumn {
    items(10) {
        Row {
            // content
        }
    }

    items(5) {
        Row {
            // content
        }
    }
}

2 ответа

Если вы хотите добавить рамку к отдельному элементу, просто добавьте в содержимое элемента Composable с модификатором:

      items(10) {
        Row(
            modifier = Modifier
                .fillMaxWidth()
                .padding(2.dp)
                .border(width = 1.dp, color = Blue200, shape = RoundedCornerShape(8.dp))
                .padding(2.dp)
       ){ /** ... */ }
}

Если вы хотите добавить границу вокруг всехitemsблок можно создавать разныеborderмодификаторы для применения к каждому элементу.
Что-то вроде:

      //border
val strokeWidth: Dp = 2.dp
val strokeColor: Color = Blue500
val cornerRadius: Dp = 8.dp

//background shape
val topShape = RoundedCornerShape(topStart = cornerRadius, topEnd = cornerRadius)
val bottomShape = RoundedCornerShape(bottomStart = cornerRadius, bottomEnd = cornerRadius)

LazyColumn {
    val itemCount = 10
    var shape : Shape
    var borderModifier : Modifier

    items(itemCount) { index ->
        when (index) {
            0 -> {
                //First item. Only top border
                shape = topShape
                borderModifier = Modifier.topBorder(strokeWidth,strokeColor,cornerRadius)
            }
            itemCount -1 -> {
                //last item. Only bottom border
                shape = bottomShape
                borderModifier = Modifier.bottomBorder(strokeWidth,strokeColor,cornerRadius)
            }
            else -> {
                //Other items. Only side border
                shape = RectangleShape
                borderModifier = Modifier.sideBorder(strokeWidth,strokeColor,cornerRadius)
            }
        }

        Row(
            modifier = Modifier
                .fillMaxWidth()
                .clip(shape)
                .background(Teal200)
                .then(borderModifier)
                .padding(4.dp)
        ) {
            Text(text = "Item: $index")
        }
    }
}

где:

      fun Modifier.topBorder(strokeWidth: Dp, color: Color, cornerRadiusDp: Dp) = composed(
    factory = {
        val density = LocalDensity.current
        val strokeWidthPx = density.run { strokeWidth.toPx() }
        val cornerRadiusPx = density.run { cornerRadiusDp.toPx() }

        Modifier.drawBehind {
            val width = size.width
            val height = size.height

            drawLine(
                color = color,
                start = Offset(x = 0f, y = height),
                end = Offset(x = 0f, y = cornerRadiusPx),
                strokeWidth = strokeWidthPx
            )

            drawArc(
                color = color,
                startAngle = 180f,
                sweepAngle = 90f,
                useCenter = false,
                topLeft = Offset.Zero,
                size = Size(cornerRadiusPx * 2, cornerRadiusPx * 2),
                style = Stroke(width = strokeWidthPx)
            )

            drawLine(
                color = color,
                start = Offset(x = cornerRadiusPx, y = 0f),
                end = Offset(x = width - cornerRadiusPx, y = 0f),
                strokeWidth = strokeWidthPx
            )

            drawArc(
                color = color,
                startAngle = 270f,
                sweepAngle = 90f,
                useCenter = false,
                topLeft = Offset(x = width - cornerRadiusPx * 2, y = 0f),
                size = Size(cornerRadiusPx * 2, cornerRadiusPx * 2),
                style = Stroke(width = strokeWidthPx)
            )

            drawLine(
                color = color,
                start = Offset(x = width, y = height),
                end = Offset(x = width, y = cornerRadiusPx),
                strokeWidth = strokeWidthPx
            )
        }
    }
)

fun Modifier.bottomBorder(strokeWidth: Dp, color: Color, cornerRadiusDp: Dp) = composed(
    factory = {
        val density = LocalDensity.current
        val strokeWidthPx = density.run { strokeWidth.toPx() }
        val cornerRadiusPx = density.run { cornerRadiusDp.toPx() }

        Modifier.drawBehind {
            val width = size.width
            val height = size.height

            drawLine(
                color = color,
                start = Offset(x = 0f, y = 0f),
                end = Offset(x = 0f, y = height-cornerRadiusPx),
                strokeWidth = strokeWidthPx
            )

            drawArc(
                color = color,
                startAngle = 90f,
                sweepAngle = 90f,
                useCenter = false,
                topLeft = Offset(x = 0f, y = height - cornerRadiusPx * 2),
                size = Size(cornerRadiusPx * 2, cornerRadiusPx * 2),
                style = Stroke(width = strokeWidthPx)
            )

            drawLine(
                color = color,
                start = Offset(x = cornerRadiusPx, y = height),
                end = Offset(x = width - cornerRadiusPx, y = height),
                strokeWidth = strokeWidthPx
            )

            drawArc(
                color = color,
                startAngle = 0f,
                sweepAngle = 90f,
                useCenter = false,
                topLeft = Offset(x = width - cornerRadiusPx * 2, y = height - cornerRadiusPx * 2),
                size = Size(cornerRadiusPx * 2, cornerRadiusPx * 2),
                style = Stroke(width = strokeWidthPx)
            )

            drawLine(
                color = color,
                start = Offset(x = width, y = 0f),
                end = Offset(x = width, y = height - cornerRadiusPx),
                strokeWidth = strokeWidthPx
            )
        }
    }
)

fun Modifier.sideBorder(strokeWidth: Dp, color: Color, cornerRadiusDp: Dp) = composed(
    factory = {
        val density = LocalDensity.current
        val strokeWidthPx = density.run { strokeWidth.toPx() }
        val cornerRadiusPx = density.run { cornerRadiusDp.toPx() }

        Modifier.drawBehind {
            val width = size.width
            val height = size.height

            drawLine(
                color = color,
                start = Offset(x = 0f, y = 0f),
                end = Offset(x = 0f, y = height),
                strokeWidth = strokeWidthPx
            )

            drawLine(
                color = color,
                start = Offset(x = width, y = 0f),
                end = Offset(x = width, y = height),
                strokeWidth = strokeWidthPx
            )
        }
    }
)

Вы можете нарисовать границу вокруг всего списка, используя модификатор border и RoundedCornerShape:

      LazyColumn(modifier.border(width = 1.dp, color = Color.Red, shape = RoundedCornerShape(1.dp)))

Или вокруг каждого элемента, применяя то же самое к строкам:

      Row(modifier.border(width = 1.dp, color = Color.Green, shape = RoundedCornerShape(1.dp)))