Android带阴影的弧形Toolbar/CardView实现问题
实现Toolbar/CardView底部弧形并保留正确阴影效果
我来帮你搞定这个问题——自定义弧形背景后丢失阴影或者阴影不贴合的情况确实很常见,咱们分两种控件分别解决:
一、Toolbar 底部弧形 + 保留阴影
你之前用layer-list作为背景导致elevation失效,是因为自定义背景会覆盖Toolbar默认的阴影实现。这里给你两种可行方案:
方案1:用AppBarLayout包裹(快速实现)
这种方法最简单,把Toolbar放在AppBarLayout里,让AppBarLayout负责显示阴影,Toolbar只专注于展示弧形背景:
<com.google.android.material.appbar.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:elevation="8dp"> <androidx.appcompat.widget.Toolbar android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@drawable/bg_toolbar" /> </com.google.android.material.appbar.AppBarLayout>
方案2:自定义OutlineProvider(阴影精准贴合弧形)
如果想要阴影完全跟着弧形轮廓走,就给Toolbar设置自定义轮廓提供者:
- 保留你原来的
bg_toolbar.xml背景不变 - 在代码中添加如下逻辑:
val toolbar = findViewById<Toolbar>(R.id.toolbar) toolbar.outlineProvider = object : ViewOutlineProvider() { override fun getOutline(view: View, outline: Outline) { // 这里的参数要和你layer-list里的椭圆参数对应 val dp100 = 100.dpToPx(view.context) val dp80 = 80.dpToPx(view.context) outline.setRoundRect( -dp100, -dp80, view.width + dp100, view.height, (view.height + dp80).toFloat() ) } } toolbar.clipToOutline = true toolbar.elevation = 8.dpToPx(view.context).toFloat() // 辅助扩展函数:dp转px fun Int.dpToPx(context: Context): Int { return (this * context.resources.displayMetrics.density).toInt() }
二、CardView 底部弧形 + 阴影贴合
CardView的阴影是基于自身形状生成的,默认矩形圆角的阴影自然不会贴合自定义弧形。推荐用MaterialCardView配合自定义形状实现:
- 创建自定义弧形形状资源
shape_card_bottom_arc.xml:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="@color/white" /> <!-- pathData定义底部弧形,可调整A后面的两个数值改变弧形大小 --> <path android:fillColor="@color/white" android:pathData="M0,0 L0,H LW,H LW,0 A120,120 0 0 1 0,0 Z" /> </shape>
- 在布局中使用MaterialCardView并关联自定义形状:
<com.google.android.material.card.MaterialCardView android:layout_width="match_parent" android:layout_height="220dp" app:cardElevation="8dp" app:shapeAppearance="@style/CardBottomArcStyle"> <!-- 这里放CardView的内部内容 --> </com.google.android.material.card.MaterialCardView>
- 在styles.xml中定义对应的形状样式:
<style name="CardBottomArcStyle" parent="ShapeAppearance.MaterialComponents.CardView"> <item name="android:background">@drawable/shape_card_bottom_arc</item> </style>
这样设置后,CardView的阴影就会完全贴合底部弧形的轮廓了。
内容的提问来源于stack exchange,提问作者Hamza Ahmed Khan




