为卡片的上半部分添加边框,并与角半径组合

use*_*265 4 android kotlin android-jetpack-compose

我想在具有角半径 (10dp) 的 Card 组件的上半部分添加边框。因此,只有底部缺失,卡片的其余部分的笔划为 1dp。(有点像U型和倒U型)

我想对具有底角半径且顶部缺失的卡片执行相同的操作。

我尝试设计自定义形状,但它不尊重卡片的形状。

// this is just a line but it doesn't respect the card corner radius? 

private fun createShape(thickness: Float) : Shape {
    return GenericShape { size, _ ->
        moveTo(0f,0f)
        lineTo(0f, size.height)
        lineTo(thickness, size.height)
        lineTo(thickness, 0f)
        lineTo(0f, thickness)
    }
}


val thickness = with(LocalDensity.current) {
    1.dp.toPx()
}
Card(
    shape = RoundedCornerShape(topEnd = 10.dp, topStart = 10.dp, bottomEnd = 0.dp, bottomStart = 0.dp),
    modifier = Modifier
        .border(BorderStroke(width = 1.dp, color = Color.Black), createShape(thickness))

) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

Thr*_*ian 6

边框似乎不允许打开形状,即使您绘制 3 条线,也会强制形状关闭,因为您需要使用 Modifier.drawBehind 或 Modifier.drawWithContent。

在此输入图像描述

创建了一个Modifier绘制 u 形边框的

fun Modifier.semiBorder(strokeWidth: Dp, color: Color, cornerRadiusDp: Dp) = composed(
    factory = {
        val density = LocalDensity.current
        val strokeWidthPx = density.run { strokeWidth.toPx() }
        val cornerRadius = 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 = cornerRadius),
                strokeWidth = strokeWidthPx
            )

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


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

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

            drawLine(
                color = color,
                start = Offset(x = width, y = height),
                end = Offset(x = width, y = cornerRadius),
                strokeWidth = strokeWidthPx
            )
        }
    }
)
Run Code Online (Sandbox Code Playgroud)

用法

@Composable
private fun UShapeBorderSample() {
    Card(
        shape = RoundedCornerShape(
            topEnd = 10.dp,
            topStart = 10.dp,
            bottomEnd = 0.dp,
            bottomStart = 0.dp
        ),
        modifier = Modifier
            .semiBorder(1.dp, Color.Black, 10.dp)

    ) {
        Box(
            modifier = Modifier
                .size(150.dp)
                .background(Color.White),
            contentAlignment = Alignment.Center
        ) {
            Text("Hello World")
        }
    }

    Spacer(modifier = Modifier.height(10.dp))

    Card(
        shape = RoundedCornerShape(
            topEnd = 20.dp,
            topStart = 20.dp,
            bottomEnd = 0.dp,
            bottomStart = 0.dp
        ),
        modifier = Modifier
            .semiBorder(1.dp, Color.Black, 20.dp)

    ) {
        Box(
            modifier = Modifier
                .size(150.dp)
                .background(Color.White),
            contentAlignment = Alignment.Center
        ) {
            Text("Hello World")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您需要使用圆弧来创建圆角。创建形状时,您不会传递厚度,而是传递形状的半径。绘制边框时需要指定厚度。您绘制的是一个宽度为 1.dp 的矩形。

在此输入图像描述

@Composable
private fun createShape(cornerRadius: Dp): Shape {

    val density = LocalDensity.current
    return GenericShape { size, _ ->

        val width = size.width
        val height = size.height
        val cornerRadiusPx = density.run { cornerRadius.toPx() }

        moveTo(0f, height)

        // Vertical line on left size
        lineTo(0f, cornerRadiusPx * 2)

        arcTo(
            rect = Rect(
                offset = Offset.Zero,
                size = Size(cornerRadiusPx * 2, cornerRadiusPx * 2)
            ),
            startAngleDegrees = 180f,
            sweepAngleDegrees = 90f,
            forceMoveTo = false
        )

        lineTo(width - cornerRadiusPx * 2, 0f)
        arcTo(
            rect = Rect(
                offset = Offset(width - cornerRadiusPx * 2, 0f),
                size = Size(cornerRadiusPx * 2, cornerRadiusPx * 2)
            ),
            startAngleDegrees = 270f,
            sweepAngleDegrees = 90f,
            forceMoveTo = false
        )
        // Vertical line on right size
        lineTo(width, height)

    }
}
Run Code Online (Sandbox Code Playgroud)

用法

@Composable
private fun UShapeBorderSample() {
    Card(
        shape = RoundedCornerShape(
            topEnd = 10.dp,
            topStart = 10.dp,
            bottomEnd = 0.dp,
            bottomStart = 0.dp
        ),
        modifier = Modifier
            .border(BorderStroke(width = 1.dp, color = Color.Black), createShape(10.dp))

    ) {
        Box(modifier = Modifier
            .size(200.dp)
            .background(Color.White),
            contentAlignment = Alignment.Center
        ) {
            Text("Hello World")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

边框不尊重形状,因为它是一个绘图,但它CardBox幕后使用形状,Modifier.clip()其本身就是Modifier.graphicsLayer{clip}在图层上应用操作。

您可以查看有关剪辑和边框的答案以了解差异。

/sf/answers/5116416721/

  • 旋转 DrawScope 内绘制的内容非常容易。添加一个用于旋转的布尔标志,并将drawLine和drawArc包装在rotate(angle){...//drawing here}中,如这些答案/sf/answers/5231142941/和https://stackoverflow.com /a/74674284/5457853 (2认同)