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

Jetpack Compose实现图片局部(底部)模糊/毛玻璃效果方案问询

Jetpack Compose 实现图片局部高效模糊的最优方案

核心结论

RenderScript 已在 Android 12 及以上版本被弃用,官方推荐使用 Jetpack RenderScript Toolkit 做跨版本高效模糊;结合 Compose 的 Canvas API 和图片加载库(如 Coil),可以实现适配 URL 图片的局部模糊效果,同时保证性能。

具体实现步骤

1. 添加依赖

首先引入必要的库:

// Coil 用于加载 URL 图片
implementation("io.coil-kt:coil-compose:2.4.0")
// RenderScript Toolkit 用于高效模糊(兼容 API 16+)
implementation("androidx.renderscript:renderscript-toolkit:1.0.0")

2. 加载 URL 图片并获取 ImageBitmap

使用 Coil 的 rememberAsyncImagePainter 加载网络图片,通过 painter.state 获取成功加载的 ImageBitmap:

val painter = rememberAsyncImagePainter(
    model = "https://example.com/your-image.jpg",
    builder = {
        crossfade(true)
    }
)
val imageBitmap = remember(painter.state) {
    if (painter.state is AsyncImagePainter.State.Success) {
        (painter.state as AsyncImagePainter.State.Success).result.drawable.toBitmap().asImageBitmap()
    } else null
}

3. 缓存模糊后的局部位图

为避免重复计算,用 remember 和 derivedStateOf 缓存模糊后的区域,仅当原图、模糊参数或区域尺寸变化时重新生成:

val blurRadius = 16f // 模糊半径,值越大越模糊
val blurAreaHeight = 100.dp // 底部模糊区域高度
val blurAreaHeightPx = with(LocalDensity.current) { blurAreaHeight.toPx() }

val blurredBitmap by remember(imageBitmap, blurRadius, blurAreaHeightPx) {
    derivedStateOf {
        imageBitmap?.let { bitmap ->
            // 裁剪底部需要模糊的区域
            val sourceRect = Rect(
                left = 0,
                top = (bitmap.height - blurAreaHeightPx).toInt(),
                right = bitmap.width,
                bottom = bitmap.height
            )
            val croppedBitmap = Bitmap.createBitmap(
                bitmap.asAndroidBitmap(),
                sourceRect.left,
                sourceRect.top,
                sourceRect.width(),
                sourceRect.height()
            )
            // 使用 RenderScript Toolkit 执行模糊
            RenderScriptToolkit.blur(croppedBitmap, blurRadius).asImageBitmap()
        }
    }
}

4. 在 Canvas 中绘制原图和模糊区域

通过 Canvas 先绘制完整原图,再在底部叠加模糊后的区域:

Box(modifier = Modifier.fillMaxSize()) {
    imageBitmap?.let { bitmap ->
        Canvas(modifier = Modifier.fillMaxSize()) {
            // 绘制原图
            drawImage(bitmap)
            // 绘制底部模糊区域
            blurredBitmap?.let { blurred ->
                drawImage(
                    image = blurred,
                    topLeft = Offset(0f, size.height - blurAreaHeightPx)
                )
            }
        }
    }
    // 加载中占位符
    if (painter.state is AsyncImagePainter.State.Loading) {
        CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
    }
}

性能优化要点

  • 缓存复用:用 remember 和 derivedStateOf 缓存模糊后的位图,避免每次重组都重新计算。
  • 缩小计算范围:仅裁剪需要模糊的区域进行处理,而非模糊整张图。
  • 异步处理:如果模糊计算耗时(大尺寸图或大模糊半径),可以将模糊逻辑放到 LaunchedEffect 中异步执行,避免阻塞 UI 线程。

Android 12+ 替代方案

如果只需要适配 Android 12(API 31)及以上,可以使用系统原生的 BlurEffect,通过 AndroidView 包裹 ImageView 实现:

AndroidView(modifier = Modifier.fillMaxSize(), factory = { context ->
    ImageView(context).apply {
        scaleType = ImageView.ScaleType.CENTER_CROP
        // 加载图片(可使用 Coil 的 ViewTarget)
        coil.load("https://example.com/your-image.jpg") {
            crossfade(true)
        }
        // 添加底部模糊遮罩
        val blurEffect = BlurEffect().apply {
            radius = 16f
        }
        val maskDrawable = ColorDrawable(Color.TRANSPARENT).apply {
            bounds = Rect(0, height - blurAreaHeightPx.toInt(), width, height)
        }
        foreground = BlurMaskDrawable(blurEffect).apply {
            setMask(maskDrawable)
        }
    }
})

不过这种方式依赖 View 系统,Compose 原生的 Canvas 方案在跨版本兼容性和渲染流畅度上更优。

内容的提问来源于stack exchange,提问作者Syeda Zunaira

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 12:21:01