You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 14:33:18