如何使用Jetpack Compose绘制两个圆形及指定形状?
Jetpack Compose 实现目标形状及绘制圆形
一、绘制两个圆形
在Compose里有两种常用的圆形实现方式:
1. 快速创建圆形View
通过Modifier.clip(CircleShape)配合背景色,就能快速生成圆形组件:
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) { Box( modifier = Modifier .size(60.dp) .clip(CircleShape) .background(Color.Blue) ) Box( modifier = Modifier .size(60.dp) .clip(CircleShape) .background(Color.Red) ) }
2. Canvas灵活绘制
如果需要自定义位置、边框等细节,用Canvas的drawCircle方法:
Canvas(modifier = Modifier.size(200.dp)) { // 填充圆形,中心在画布左半区 drawCircle( color = Color.Blue, radius = 30.dp.toPx(), center = Offset(size.width / 4, size.height / 2) ) // 带边框的圆形,中心在画布右半区 drawCircle( color = Color.Red, radius = 30.dp.toPx(), center = Offset(size.width * 3 / 4, size.height / 2), style = Stroke(width = 2.dp.toPx()) ) }
二、实现目标形状(参考配图)
从配图来看,该形状是底部为圆角矩形、顶部左右两侧向外突出半圆的自定义造型,以下两种方式可实现:
方法1:自定义可复用Shape
class CustomShape(private val cornerRadius: Dp, private val topCircleRadius: Dp) : Shape { override fun createOutline( size: Size, layoutDirection: LayoutDirection, density: Density ): Outline { val cornerRadiusPx = cornerRadius.toPx(density) val topCircleRadiusPx = topCircleRadius.toPx(density) val path = Path().apply { // 从左下角圆角起点开始 moveTo(cornerRadiusPx, size.height) // 绘制底部左侧圆角 arcTo( rect = Rect( left = 0f, top = size.height - 2 * cornerRadiusPx, right = 2 * cornerRadiusPx, bottom = size.height ), startAngleDegrees = 90f, sweepAngleDegrees = 90f, forceMoveTo = false ) // 绘制左侧边到顶部半圆起点 lineTo(0f, topCircleRadiusPx) // 绘制左侧顶部外凸半圆 arcTo( rect = Rect( left = -topCircleRadiusPx, top = 0f, right = topCircleRadiusPx, bottom = 2 * topCircleRadiusPx ), startAngleDegrees = 180f, sweepAngleDegrees = -180f, forceMoveTo = false ) // 绘制顶部水平线到右侧半圆起点 lineTo(size.width - topCircleRadiusPx, 0f) // 绘制右侧顶部外凸半圆 arcTo( rect = Rect( left = size.width - topCircleRadiusPx, top = 0f, right = size.width + topCircleRadiusPx, bottom = 2 * topCircleRadiusPx ), startAngleDegrees = 0f, sweepAngleDegrees = -180f, forceMoveTo = false ) // 绘制右侧边到右下角圆角起点 lineTo(size.width, size.height - cornerRadiusPx) // 绘制底部右侧圆角 arcTo( rect = Rect( left = size.width - 2 * cornerRadiusPx, top = size.height - 2 * cornerRadiusPx, right = size.width, bottom = size.height ), startAngleDegrees = 0f, sweepAngleDegrees = 90f, forceMoveTo = false ) // 闭合路径 close() } return Outline.Generic(path) } }
使用该自定义Shape:
Box( modifier = Modifier .size(200.dp, 150.dp) .clip(CustomShape(cornerRadius = 16.dp, topCircleRadius = 24.dp)) .background(Color.Green) )
方法2:Canvas直接绘制路径
如果不需要复用,直接在Canvas中绘制:
Canvas(modifier = Modifier.size(200.dp, 150.dp)) { val cornerRadiusPx = 16.dp.toPx() val topCircleRadiusPx = 24.dp.toPx() val path = Path().apply { moveTo(cornerRadiusPx, size.height) arcTo( Rect(0f, size.height - 2 * cornerRadiusPx, 2 * cornerRadiusPx, size.height), 90f, 90f, false ) lineTo(0f, topCircleRadiusPx) arcTo( Rect(-topCircleRadiusPx, 0f, topCircleRadiusPx, 2 * topCircleRadiusPx), 180f, -180f, false ) lineTo(size.width - topCircleRadiusPx, 0f) arcTo( Rect(size.width - topCircleRadiusPx, 0f, size.width + topCircleRadiusPx, 2 * topCircleRadiusPx), 0f, -180f, false ) lineTo(size.width, size.height - cornerRadiusPx) arcTo( Rect(size.width - 2 * cornerRadiusPx, size.height - 2 * cornerRadiusPx, size.width, size.height), 0f, 90f, false ) close() } // 填充形状 drawPath(path, color = Color.Green) // 可选:绘制边框 drawPath(path, color = Color.Black, style = Stroke(2.dp.toPx())) }
内容的提问来源于stack exchange,提问作者Null
相关产品推荐
相关产品推荐

