Glide 4:如何为圆形裁剪头像及RoundedCorners圆角头像添加阴影?
嘿,刚好我之前也遇到过类似的问题,来给你捋捋Glide 4里给圆角/圆形头像加阴影的方案~
给Glide 4加载的圆角/圆形头像添加阴影
先说结论:Glide 4没有内置的阴影实现
因为Glide的核心是图片加载与变换,而阴影本质是View层面的视觉效果,所以官方没有直接提供这个功能,但我们有两种靠谱的解决思路:用现成的View组件(比如CardView),或者自定义Glide的Transformation。
一、圆角头像加阴影的两种方法
方法1:用CardView包裹ImageView(最简单推荐!)
这是最省心的方案,不用写任何自定义代码,利用CardView自带的阴影和圆角属性就能搞定:
- 布局里用CardView把ImageView包起来,设置好
cardCornerRadius(圆角)和cardElevation(阴影高度) - Glide加载图片时用
RoundedCorners变换,保证圆角值和CardView一致 - 记得给ImageView设置
scaleType="centerCrop",避免图片和CardView的圆角错位
布局代码示例:
<androidx.cardview.widget.CardView android:layout_width="100dp" android:layout_height="100dp" app:cardCornerRadius="16dp" <!-- 和Glide的圆角保持一致 --> app:cardElevation="8dp" <!-- 阴影高度,值越大阴影越明显 --> app:cardUseCompatPadding="true"> <!-- 避免阴影被父容器裁剪 --> <ImageView android:id="@+id/rounded_avatar" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop"/> </androidx.cardview.widget.CardView>
Glide加载代码(Kotlin):
// 先把dp转成px,因为Glide的RoundedCorners参数是px val cornerRadiusPx = (16 * resources.displayMetrics.density).toInt() Glide.with(this) .load("你的头像URL") .transform(RoundedCorners(cornerRadiusPx)) .into(binding.roundedAvatar)
方法2:自定义Glide Transformation(定制化需求)
如果不想用CardView,比如需要更独特的阴影颜色、模糊度,可以自己写一个Transformation,把阴影直接绘制到图片上:
自定义Transformation代码:
class RoundedCornerWithShadowTransformation( private val radius: Float, // 圆角半径(px) private val shadowRadius: Float, // 阴影模糊半径 private val shadowOffsetX: Float, // 阴影X偏移 private val shadowOffsetY: Float, // 阴影Y偏移 private val shadowColor: Int // 阴影颜色 ) : BitmapTransformation() { override fun transform( context: Context, pool: BitmapPool, toTransform: Bitmap, outWidth: Int, outHeight: Int ): Bitmap { // 创建能容纳阴影的Bitmap,宽高要预留阴影空间 val shadowedWidth = (toTransform.width + shadowRadius * 2 + abs(shadowOffsetX)).toInt() val shadowedHeight = (toTransform.height + shadowRadius * 2 + abs(shadowOffsetY)).toInt() val shadowedBitmap = pool.get(shadowedWidth, shadowedHeight, Bitmap.Config.ARGB_8888) shadowedBitmap.setHasAlpha(true) val canvas = Canvas(shadowedBitmap) val shadowPaint = Paint().apply { isAntiAlias = true setShadowLayer(shadowRadius, shadowOffsetX, shadowOffsetY, shadowColor) } // 计算图片绘制的起始位置,让图片居中 val startX = shadowRadius + abs(shadowOffsetX) val startY = shadowRadius + abs(shadowOffsetY) val rectF = RectF(startX, startY, startX + toTransform.width, startY + toTransform.height) // 先画圆角阴影背景 canvas.drawRoundRect(rectF, radius, radius, shadowPaint) // 裁剪圆角区域,再绘制原图 val clipPath = Path().apply { addRoundRect(rectF, radius, radius, Path.Direction.CW) } canvas.clipPath(clipPath) canvas.drawBitmap(toTransform, startX, startY, null) return shadowedBitmap } override fun updateDiskCacheKey(messageDigest: MessageDigest) { // 生成唯一的缓存key,避免不同参数的Transformation混淆缓存 val key = "rounded_shadow_$radius-$shadowRadius-$shadowOffsetX-$shadowOffsetY-$shadowColor" messageDigest.update(key.toByteArray()) } }
使用方式:
val dp = resources.displayMetrics.density Glide.with(this) .load("你的头像URL") .transform( RoundedCornerWithShadowTransformation( radius = 16 * dp, shadowRadius = 4 * dp, shadowOffsetX = 0f, shadowOffsetY = 2 * dp, shadowColor = Color.parseColor("#40000000") // 半透明黑色阴影 ) ) .into(binding.roundedAvatar)
二、圆形裁剪图片加阴影的方法
思路和圆角完全一致,只是把圆角换成圆形:
方法1:CardView快速实现
把CardView的cardCornerRadius设置为宽高的一半,Glide用CircleCrop变换:
布局代码:
<androidx.cardview.widget.CardView android:layout_width="100dp" android:layout_height="100dp" app:cardCornerRadius="50dp" <!-- 宽高的一半,变成圆形 --> app:cardElevation="8dp" app:cardUseCompatPadding="true"> <ImageView android:id="@+id/circular_avatar" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop"/> </androidx.cardview.widget.CardView>
Glide加载代码:
Glide.with(this) .load("你的头像URL") .transform(CircleCrop()) .into(binding.circularAvatar)
方法2:自定义圆形带阴影的Transformation
如果需要定制阴影,写一个圆形版的Transformation:
自定义Transformation代码:
class CircleWithShadowTransformation( private val shadowRadius: Float, private val shadowOffsetX: Float, private val shadowOffsetY: Float, private val shadowColor: Int ) : BitmapTransformation() { override fun transform( context: Context, pool: BitmapPool, toTransform: Bitmap, outWidth: Int, outHeight: Int ): Bitmap { val imageSize = max(toTransform.width, toTransform.height) // 预留阴影空间后的总尺寸 val shadowedSize = imageSize + shadowRadius * 2 + max(abs(shadowOffsetX), abs(shadowOffsetY)) val shadowedBitmap = pool.get(shadowedSize.toInt(), shadowedSize.toInt(), Bitmap.Config.ARGB_8888) shadowedBitmap.setHasAlpha(true) val canvas = Canvas(shadowedBitmap) val shadowPaint = Paint().apply { isAntiAlias = true setShadowLayer(shadowRadius, shadowOffsetX, shadowOffsetY, shadowColor) } val centerX = shadowedBitmap.width / 2f val centerY = shadowedBitmap.height / 2f val circleRadius = imageSize / 2f // 绘制圆形阴影 canvas.drawCircle(centerX, centerY, circleRadius, shadowPaint) // 裁剪圆形区域 val clipPath = Path().apply { addCircle(centerX, centerY, circleRadius, Path.Direction.CW) } canvas.clipPath(clipPath) // 居中绘制原图 val dx = centerX - toTransform.width / 2f val dy = centerY - toTransform.height / 2f canvas.drawBitmap(toTransform, dx, dy, null) return shadowedBitmap } override fun updateDiskCacheKey(messageDigest: MessageDigest) { val key = "circle_shadow_$shadowRadius-$shadowOffsetX-$shadowOffsetY-$shadowColor" messageDigest.update(key.toByteArray()) } }
使用方式:
val dp = resources.displayMetrics.density Glide.with(this) .load("你的头像URL") .transform( CircleWithShadowTransformation( shadowRadius = 4 * dp, shadowOffsetX = 0f, shadowOffsetY = 2 * dp, shadowColor = Color.parseColor("#40000000") ) ) .into(binding.circularAvatar)
最后总结
- 优先用CardView方案,代码少、性能好,适配也没问题
- 只有当需要特殊阴影效果(比如渐变阴影、自定义颜色)时,再考虑自定义Transformation
- Glide本身没有内置阴影功能,因为阴影属于View的视觉装饰,而非图片本身的变换
内容的提问来源于stack exchange,提问作者Cyrus the Great
相关产品推荐
相关产品推荐

