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

Android实现带左右圆形切口的矩形背景 保留卡片阴影

实现带两侧内凹圆形切口的卡片(保留阴影效果)

我正在尝试实现如下图所示的视图效果:
效果示意图
该效果为矩形背景,矩形的左右两侧各有一个向内凹陷的圆形切口。
我尝试使用如下XML代码实现:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <corners
                android:topLeftRadius="8dp"
                android:topRightRadius="8dp"
                android:bottomLeftRadius="4dp"
                android:bottomRightRadius="4dp" />

            <size
                android:width="300dp"
                android:height="200dp" />
            <solid android:color="#FFFFFF" />
        </shape>
    </item>

    <item
        android:left="-10dp"
        android:right="290dp"
        android:top="40dp"
        android:bottom="40dp">
        <shape android:shape="oval">
            <solid android:color="#00000000" />
        </shape>
    </item>

    <item
        android:left="290dp"
        android:right="-10dp"
        android:top="40dp"
        android:bottom="40dp">
        <shape android:shape="oval">
            <solid android:color="#00000000" />
        </shape>
    </item>

    <item
        android:left="10dp"
        android:right="10dp"
        android:top="50dp">
        <shape android:shape="line">
            <stroke
                android:width="1dp"
                android:color="#EEEEEE"/>
        </shape>
    </item>
</layer-list>

但实际运行后左右两侧的圆形切口并未正常显示,请问是否有可行方案可以实现该圆形切口效果,同时不会丢失卡片的阴影效果?


解决方案

原有代码不生效的核心原因:Android原生layer-list的shape绘制不支持透明像素挖空逻辑,你叠在上方的透明圆形只是透明层覆盖在白色矩形上,不会把矩形对应位置的白色抠除,自然无法显示凹陷切口。
推荐使用Material组件库的MaterialShapeDrawable实现,既可以精准绘制边缘内凹切口,也原生支持阴影效果,无需复杂自定义View:

  • 前置准备:确保项目已引入Material Components依赖
  • 代码中给目标控件设置MaterialShapeDrawable作为背景,示例如下:
// 单位转换扩展:dp转px
fun Float.dp2px(): Float = this * Resources.getSystem().displayMetrics.density

val shapeModel = ShapeAppearanceModel.builder()
    // 配置四个角的圆角,和你原有需求一致
    .setTopLeftCorner(CornerFamily.ROUNDED, 8f.dp2px())
    .setTopRightCorner(CornerFamily.ROUNDED, 8f.dp2px())
    .setBottomLeftCorner(CornerFamily.ROUNDED, 4f.dp2px())
    .setBottomRightCorner(CornerFamily.ROUNDED, 4f.dp2px())
    // 配置左侧内凹圆形切口,位置在卡片垂直中点,切口半径10dp可按需调整
    .setLeftEdge(
        CutoutEdgeTreatment(
            floatArrayOf(200f.dp2px() / 2),
            10f.dp2px(),
            false
        )
    )
    // 配置右侧内凹圆形切口
    .setRightEdge(
        CutoutEdgeTreatment(
            floatArrayOf(200f.dp2px() / 2),
            10f.dp2px(),
            false
        )
    )
    .build()

val cardBg = MaterialShapeDrawable(shapeModel).apply {
    fillColor = ColorStateList.valueOf(Color.WHITE)
    // 开启阴影兼容,设置阴影大小、颜色
    shadowCompatibilityMode = MaterialShapeDrawable.SHADOW_COMPAT_MODE_ALWAYS
    elevation = 4f.dp2px()
    setShadowColor(Color.parseColor("#40000000"))
}

// 将构造好的背景设置给卡片控件
yourCardView.background = cardBg
  • 卡片中间的分隔线不建议写在shape里,直接在布局中添加一个高度1dp、颜色#EEEEEE的View,放在对应位置即可,调整位置更灵活。

如果需要完全用XML实现,也可以自定义View用PorterDuffXfermode的DST_OUT模式先把矩形左右两侧挖去半圆,再开启软件层面的阴影绘制,但这种方式实现的阴影效果不如Material方案自然,且需要处理图层类型,不推荐优先使用。


内容的提问来源于stack exchange,提问作者Abdulmalek Dery

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 09:54:22