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
相关产品推荐
相关产品推荐

