android shape drawable 不支持 bottomonly 圆角:android:radius 全局生效,单边属性如 android:bottomleftradius 在 api

shape bottomOnly 圆角在 XML 里根本不存在
Android 的 shape drawable 不支持只设底部两个角的圆角——android:radius 是全局生效的,android:topLeftRadius 等单边属性只有在 android:shape="rectangle" 且 API ≥ 23 时才有效,但它们**不能单独控制底边**;低版本(尤其是主流兼容的 API 16–22)下这些属性会被完全忽略。
常见错误现象:android:bottomLeftRadius 和 android:bottomRightRadius 写了没反应,预览和运行都还是直角。
使用场景:你想要一个上直角、下圆角的卡片背景,比如对话气泡或输入框底部装饰。
实操建议:
- API ≥ 23 可用
corners标签配合四个独立 radius 属性,但必须同时写全四个(哪怕设为0dp),例如:<corners android:topLeftRadius="0dp" android:topRightRadius="0dp" android:bottomLeftRadius="8dp" android:bottomRightRadius="8dp" />
- 要兼容低版本?别碰
shape单独实现——改用layer-list+ 两个shape(一个全圆角矩形裁掉上半部分,一个直角矩形盖住上半部) - 更推荐直接切图或改用
MaterialCardView配合app:shapeAppearanceOverlay,它底层用的是ShapeAppearanceModel,对单边圆角支持稳定
用 layer-list 模拟 bottom-only 圆角(兼容 API 16+)
这是最稳妥的手动方案,原理是“遮罩”:先画一个完整圆角矩形,再用一个直角矩形把它顶部盖住,只露出底部圆角区域。
关键点在于两个层的尺寸和位置必须精确对齐,否则会出现错位或漏白。
实操建议:
- 外层
shape设大一点圆角(比如16dp),确保底部足够圆润 - 内层直角
shape的android:height要等于你希望“被削掉”的高度(比如想留出 48dp 高的圆角区,就让直角层高calc(总高 - 48dp)) - 用
android:top把直角层往下推,让它刚好盖住上半部分,例如:<item android:top="48dp"><shape><solid android:color="@android:color/transparent"/></shape></item>
- 注意:所有尺寸单位统一用
dp,不要混用px或sp
MaterialCardView 的 app:shapeAppearanceOverlay 更省心
如果你项目已引入 Material Components,这是最干净的解法。它不依赖 XML shape 的历史包袱,而是通过 ShapeAppearanceModel 动态生成路径,底部圆角原生支持。
性能影响几乎为零,兼容性由库自身兜底(最低支持 API 14),且能和 elevation、ripple 等特性无缝共存。
实操建议:
- 在
res/values/styles.xml中定义 overlay style:<style name="BottomRounded" parent=""><item name="cornerSizeTopLeft">0dp</item><item name="cornerSizeTopRight">0dp</item><item name="cornerSizeBottomLeft">8dp</item><item name="cornerSizeBottomRight">8dp</item></style>
- 在布局中给
MaterialCardView加属性:app:shapeAppearanceOverlay="@style/BottomRounded"
- 别忘了移除 card 的默认
cardCornerRadius,否则会和 overlay 冲突
自定义 Drawable 类是最后手段
当 layer-list 太难调、Material 又不能用(比如老项目强耦合 AppCompat),可以写一个继承 Drawable 的类,重写 onDraw(),用 Path.addRoundRect() 手动构造只含底部圆角的路径。
容易踩的坑:Canvas 坐标系容易搞反,RectF 的 top 值不是从上往下算的“高度”,而是距 Canvas 顶部的距离;另外硬件加速开启时,某些 Path 操作可能被降级或失效。
实操建议:
- 务必在
onBoundsChange()里重新计算RectF,否则旋转或缩放后圆角错位 - 用
Paint.setAntiAlias(true),不然圆角边缘发虚 - 避免在
onDraw()里 new 对象(如Path、Paint),提前缓存复用
实际项目里,90% 的底部圆角需求用 MaterialCardView + shapeAppearanceOverlay 就能闭环。剩下 10% 如果卡在老框架里,layer-list 方案虽然啰嗦,但一次写对就能稳定跑五年——比反复调试自定义 Drawable 省心太多。真正麻烦的是那些把圆角逻辑硬塞进 View.onDraw 里还带手势动画的场景,那已经不是 XML 能解决的事了。










