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

Glide 4:如何为圆形裁剪头像及RoundedCorners圆角头像添加阴影?

嘿,刚好我之前也遇到过类似的问题,来给你捋捋Glide 4里给圆角/圆形头像加阴影的方案~

给Glide 4加载的圆角/圆形头像添加阴影

先说结论:Glide 4没有内置的阴影实现

因为Glide的核心是图片加载与变换,而阴影本质是View层面的视觉效果,所以官方没有直接提供这个功能,但我们有两种靠谱的解决思路:用现成的View组件(比如CardView),或者自定义Glide的Transformation。

一、圆角头像加阴影的两种方法

方法1:用CardView包裹ImageView(最简单推荐!)

这是最省心的方案,不用写任何自定义代码,利用CardView自带的阴影和圆角属性就能搞定:

  1. 布局里用CardView把ImageView包起来,设置好cardCornerRadius(圆角)和cardElevation(阴影高度)
  2. Glide加载图片时用RoundedCorners变换,保证圆角值和CardView一致
  3. 记得给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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:33:37