如何在Widget上应用notch curve实现组件凹口效果
Arrow组件凹口效果实现方案
你要实现的设计效果如下:
目前没有专门针对Arrow组件的开箱即用凹口实现,不过有两种非常简便的落地方式,效果和Floating Action Button在BottomAppBar上的凹口完全一致:
方案一:复用FAB凹口机制(零自定义路径成本)
这是最省事的实现方式,不需要自己写路径裁剪逻辑,直接复用现有组件的成熟能力:
- 把你的Arrow组件嵌套在
FloatingActionButton组件内部,把FAB的背景、默认阴影、点击水波纹效果全部设为透明,只保留Arrow本身的视觉显示 - 给承载凹口的容器组件(比如底部导航栏、工具栏)设置
cutoutShape参数,形状和你Arrow的外轮廓匹配(圆形箭头就用CircleShape,方形带圆角就用对应圆角的RoundedCornerShape) - 按照正常FAB和底部栏的嵌套逻辑摆放位置,容器会自动在Arrow停靠的位置开出适配尺寸的凹口,自动对齐、自动处理边距,不需要手动计算位置
核心代码示例:
// 承载凹口的底部栏示例 BottomAppBar( cutoutShape = CircleShape, // 凹口形状匹配Arrow外轮廓 containerColor = MaterialTheme.colorScheme.surface ) { // 底部栏其他菜单内容 } // 伪装成FAB的Arrow组件 FloatingActionButton( onClick = { /* Arrow对应的点击逻辑,无交互可传空实现 */ }, modifier = Modifier.size(24.dp), // 尺寸和你的Arrow资源大小匹配 containerColor = Color.Transparent, elevation = FloatingActionButtonDefaults.elevation(0.dp, 0.dp, 0.dp, 0.dp), // 去掉默认阴影 interactionSource = remember { MutableInteractionSource() } // 可搭配去掉默认点击效果 ) { Icon( painter = painterResource(id = R.drawable.your_arrow_icon), // 替换为你的Arrow资源 contentDescription = "箭头", tint = 你需要的箭头颜色 ) }
方案二:自定义Shape实现(适配任意场景)
如果你的Arrow不是停靠在默认支持FAB凹口的组件上,直接自定义带凹口的形状给容器做裁剪即可,灵活度最高:
- 定义凹口的尺寸参数,和你的Arrow外轮廓尺寸保持一致
- 定义凹口的坐标位置,和Arrow的摆放位置对齐
- 用Path画出带凹口的容器轮廓,通过
modifier.clip()给容器加裁剪效果即可
核心代码示例:
fun buildNotchShape( notchWidthPx: Float, notchCenterXPx: Float, isNotchAtTop: Boolean = true ) = object : Shape { override fun createOutline( size: Size, layoutDirection: LayoutDirection, density: Density ): Outline { val path = Path().apply { // 从左上角起点开始画轮廓 moveTo(0f, 0f) // 画到凹口起始位置 lineTo(notchCenterXPx - notchWidthPx/2, 0f) // 画凹口圆弧,根据凹口方向调整圆弧的外接矩形位置 arcTo( rect = Rect( left = notchCenterXPx - notchWidthPx/2, top = if (isNotchAtTop) -notchWidthPx/2 else size.height - notchWidthPx/2, right = notchCenterXPx + notchWidthPx/2, bottom = if (isNotchAtTop) notchWidthPx/2 else size.height + notchWidthPx/2 ), startAngleDegrees = 180f, sweepAngleDegrees = if (isNotchAtTop) 180f else -180f, forceMoveTo = false ) // 继续画容器剩余轮廓 lineTo(size.width, 0f) lineTo(size.width, size.height) lineTo(0f, size.height) close() } return Outline.Generic(path) } } // 使用时,根据Arrow的实际位置和尺寸动态传参生成Shape即可 val notchShape = buildNotchShape( notchWidthPx = with(LocalDensity.current) { 24.dp.toPx() }, notchCenterXPx = 300f // 替换为Arrow组件在容器上的X坐标 ) // 给容器加Modifier.clip(notchShape)即可生效
提示:如果你的Arrow外轮廓不是圆形,只需要修改Path里凹口部分的绘制逻辑,换成对应形状的贝塞尔曲线或者图形即可。
内容的提问来源于stack exchange,提问作者yazicifatihcan
相关产品推荐
相关产品推荐

