簡體   English   中英

Jetpack Compose - 邊框上帶有弧形的 CardView

[英]Jetpack Compose - CardView with Arc Shape on border

我正在嘗試在 cardview 邊框/筆划上實現低於 cardview 弧形。 已經嘗試在谷歌上搜索但沒有找到任何符合要求的相關答案。

任何線索或幫助都將得到應用。

在此處輸入圖像描述

Cirilo Bido 和 Raghunandan 的回答是一個很好的起點,您可以使用arcTo將矩形的角倒圓角,但是您不能在裁剪形狀的頂部繪制彎曲的邊緣。 您需要使用cubicTo繪制圓角邊緣和曲線以裁剪底部形狀

   val shape = GenericShape {size: Size, layoutDirection: LayoutDirection ->
                            // draw cubic on left and right sides for button space
                            cubicTo()
                        }

在此處輸入圖像描述

您可以查看此答案以使用立方體繪制。 通過結合兩者,您可以繪制該路徑。

Jetpack Compose:如何繪制這樣的路徑/線

我根據分享的文章創建了這條路徑
Raghunandan 最初,即使這是動畫 BottomBar 的驚人答案,如果您仔細觀察它也不會創建圓形,在底部它會在底部創建三角形而不是圓形,並且 OP 需要形狀並且在文章中也是不同的.

所以我使用滑塊從上面共享的鏈接創建貝塞爾曲線。 它也可以在這里作為教程使用。 如果您願意,它仍然可以調整為更精確的形狀。

在此處輸入圖像描述

我使用 x0, y0 作為參考點來設置控制點並創建了這個路徑擴展 function。

fun Path.roundedRectanglePath(
    size: Size,
    cornerRadius: Float,
    fabRadius: Float,
) {

    val centerX = size.width / 2
    val x0 = centerX - fabRadius * 1.15f
    val y0 = 0f

    // offset of the first control point (top part)
    val topControlX = x0 + fabRadius * .5f
    val topControlY = y0

    // offset of the second control point (bottom part)
    val bottomControlX = x0
    val bottomControlY = y0 + fabRadius

    // first curve
    // set the starting point of the curve (P2)
    val firstCurveStart = Offset(x0, y0)

    // set the end point for the first curve (P3)
    val firstCurveEnd = Offset(centerX, fabRadius * 1f)

    // set the first control point (C1)
    val firstCurveControlPoint1 = Offset(
        x = topControlX,
        y = topControlY
    )

    // set the second control point (C2)
    val firstCurveControlPoint2 = Offset(
        x = bottomControlX,
        y = bottomControlY
    )


    // second curve
    // end of first curve and start of second curve is the same (P3)
    val secondCurveStart = Offset(
        x = firstCurveEnd.x,
        y = firstCurveEnd.y
    )

    // end of the second curve (P4)
    val secondCurveEnd = Offset(
        x = centerX + fabRadius * 1.15f,
        y = 0f
    )

    // set the first control point of second curve (C4)
    val secondCurveControlPoint1 = Offset(
        x = secondCurveStart.x + fabRadius,
        y = bottomControlY
    )

    // set the second control point (C3)
    val secondCurveControlPoint2 = Offset(
        x = secondCurveEnd.x - fabRadius / 2,
        y = topControlY
    )


    // Top left arc
    val radius = cornerRadius * 2

    arcTo(
        rect = Rect(
            left = 0f,
            top = 0f,
            right = radius,
            bottom = radius
        ),
        startAngleDegrees = 180.0f,
        sweepAngleDegrees = 90.0f,
        forceMoveTo = false
    )



    lineTo(x = firstCurveStart.x, y = firstCurveStart.y)

    // bezier curve with (P2, C1, C2, P3)
    cubicTo(
        x1 = firstCurveControlPoint1.x,
        y1 = firstCurveControlPoint1.y,
        x2 = firstCurveControlPoint2.x,
        y2 = firstCurveControlPoint2.y,
        x3 = firstCurveEnd.x,
        y3 = firstCurveEnd.y
    )

    // bezier curve with (P3, C4, C3, P4)
    cubicTo(
        x1 = secondCurveControlPoint1.x,
        y1 = secondCurveControlPoint1.y,
        x2 = secondCurveControlPoint2.x,
        y2 = secondCurveControlPoint2.y,
        x3 = secondCurveEnd.x,
        y3 = secondCurveEnd.y
    )

    lineTo(x = size.width - cornerRadius, y = 0f)

    // Top right arc
    arcTo(
        rect = Rect(
            left = size.width - radius,
            top = 0f,
            right = size.width,
            bottom = radius
        ),
        startAngleDegrees = -90.0f,
        sweepAngleDegrees = 90.0f,
        forceMoveTo = false
    )

    lineTo(x = 0f + size.width, y = size.height - cornerRadius)

    // Bottom right arc
    arcTo(
        rect = Rect(
            left = size.width - radius,
            top = size.height - radius,
            right = size.width,
            bottom = size.height
        ),
        startAngleDegrees = 0f,
        sweepAngleDegrees = 90.0f,
        forceMoveTo = false
    )

    lineTo(x = cornerRadius, y = size.height)

    // Bottom left arc
    arcTo(
        rect = Rect(
            left = 0f,
            top = size.height - radius,
            right = radius,
            bottom = size.height
        ),
        startAngleDegrees = 90.0f,
        sweepAngleDegrees = 90.0f,
        forceMoveTo = false
    )

    lineTo(x = 0f, y = cornerRadius)
    close()
}

使用此形狀的可組合項

@Composable
private fun CustomArcShape(
    modifier: Modifier,
    elevation: Dp = 4.dp,
    color: Color = MaterialTheme.colorScheme.surface,
    contentColor: Color = contentColorFor(color),
    content: @Composable () -> Unit
) {

    val diameter = 60.dp
    val radiusDp = diameter / 2

    val cornerRadiusDp = 10.dp

    val density = LocalDensity.current
    val cutoutRadius = density.run { radiusDp.toPx() }
    val cornerRadius = density.run { cornerRadiusDp.toPx() }

    val shape = remember {
        GenericShape { size: Size, layoutDirection: LayoutDirection ->
            this.roundedRectanglePath(
                size = size,
                cornerRadius = cornerRadius,
                fabRadius = cutoutRadius * 2
            )
        }
    }

    Spacer(modifier = Modifier.height(diameter / 2))

    Box(contentAlignment = Alignment.TopCenter) {
        FloatingActionButton(
            shape = CircleShape,
            containerColor = Color(0xffD32F2F),
            modifier = Modifier
                .offset(y = -diameter / 5)
                .size(diameter)
                .drawBehind {
                    drawCircle(
                        Color.Red.copy(.5f),
                        radius = 1.3f * size.width / 2
                    )

                    drawCircle(
                        Color.Red.copy(.3f),
                        radius = 1.5f * size.width / 2
                    )

                }
                .align(Alignment.TopCenter),
            onClick = { /*TODO*/ }
        ) {
            Icon(
                tint = Color.White,
                imageVector = Icons.Filled.Close,
                contentDescription = "Close"
            )
        }

        Surface(
            modifier = modifier,
            shape = shape,
            shadowElevation = elevation,
            color = color,
            contentColor = contentColor
        ) {
            Column {
                Spacer(modifier = Modifier.height(diameter))
                content()

            }
        }
    }
}

及示范

@Composable
private fun CustomArcShapeSample() {
    Column(
        modifier = Modifier
            .fillMaxSize()
    ) {

        CustomArcShape(
            modifier = Modifier
                .padding(10.dp)
                .fillMaxWidth()
                .height(250.dp)
        ) {
            Column(
                modifier = Modifier.fillMaxSize(),
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Text(
                    "Payment Failed",
                    color = MaterialTheme.colorScheme.error,
                    fontWeight = FontWeight.Bold
                )
                Spacer(modifier = Modifier.height(10.dp))
                Text("Sorry !", fontSize = 24.sp, fontWeight = FontWeight.Bold)
                Spacer(modifier = Modifier.height(10.dp))
                Text("Your transfer to bank failed", color = Color.LightGray)
            }
        }

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

        CustomArcShape(
            modifier = Modifier
                .padding(10.dp)
                .fillMaxWidth()
                .height(250.dp)
        ) {
            Column(
                modifier = Modifier
                    .fillMaxSize()
                    .border(1.dp, Color.Green),
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Text(
                    "Payment Failed",
                    color = MaterialTheme.colorScheme.error,
                    fontWeight = FontWeight.Bold
                )
                Spacer(modifier = Modifier.height(10.dp))
                Text("Sorry !", fontSize = 24.sp, fontWeight = FontWeight.Bold)
                Spacer(modifier = Modifier.height(10.dp))
                Text("Your transfer to bank failed", color = Color.LightGray)
            }
        }

    }
}

您可能需要在自定義可組合項中繪制該弧線,我發現這篇文章可以幫助您了解在 compose 中繪制的過程!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM