我该如何在Jetpack Compose中模糊背景或创建模糊覆盖层?目前没有任何文档或资源涉及此主题。简单来说,我希望能够本地实现类似这个的效果。
这是一个已被要求的功能(仅在 Android 12 及以上版本中实现),您可能希望对其进行标记。
想法是创建一个模糊修饰符,它会像这样:
Modifier.blur(radius = 16.dp)
Modifier.blur(30.dp)
但是仅在Android 12及以上版本中支持。试图在较旧的Android版本上使用此修饰符将被忽略。
参考文献:Modifier.blur
如果使用API 31之前的早期版本,你仍然可以使用RenderScript(已弃用)或RenderScript Intrinsics Replacement Toolkit。
第一种方式:
val bitmap = BitmapFactory.decodeResource(
LocalContext.current.resources,
R.drawable.your_image
)
val rs = RenderScript.create(LocalContext.current)
val bitmapAlloc = Allocation.createFromBitmap(rs, bitmap)
ScriptIntrinsicBlur.create(rs, bitmapAlloc.element).apply {
setRadius(BLUR_RADIUS)
setInput(bitmapAlloc)
forEach(bitmapAlloc)
}
bitmapAlloc.copyTo(bitmap)
rs.destroy()
第二步需要将renderscript-toolkit模块添加到您的项目中(请参阅此处),然后使用以下命令:
val bitmap = BitmapFactory.decodeResource(
LocalContext.current.resources,
R.drawable.your_image
).let { Toolkit.blur(it, BLUR_RADIUS) }
最后,您可以像这样显示模糊位图:
Image(
bitmap = bitmap.asImageBitmap(),
"some description"
)
val picture = remember { Picture() }
var onPictureDrawn by remember { mutableStateOf(false) }
var offset by remember { mutableStateOf(IntOffset(0, 0)) }
Box(modifier = Modifier.fillMaxSize()) {
Image(
painter = painterResource(id = R.drawable.a), contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier
.fillMaxSize()
// 1 Redirect drawing into picture
.drawWithCache {
onDrawWithContent {
val pictureCanvas =
Canvas(
picture.beginRecording(
size.width.toInt(),
size.height.toInt()
)
)
draw(this, this.layoutDirection, pictureCanvas, this.size) {
this@onDrawWithContent.drawContent()
}
picture.endRecording()
onPictureDrawn = true
drawIntoCanvas { canvas -> canvas.nativeCanvas.drawPicture(picture) }
}
}
.pointerInteropFilter { motion ->
offset = IntOffset(motion.x.toInt(), motion.y.toInt())
true
}
)
...
}
从图片创建一个位图
模糊位图。
if (onPictureDrawn) { // wait until picture is fully drawn
// 2
val bitmap = createBitmapFromPicture(picture)
// 3
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { // For backward compatibility
val blurredBitmap = legacyBlurImage(
bitmap = bitmap,
blurRadio = 25f,
)
BlurImage(
modifier = Modifier,
bitmap = blurredBitmap,
offset = offset
)
} else {
BlurImage(
modifier = Modifier.blur(25.dp),
bitmap = bitmap,
offset = offset
)
}
}
@Composable
private fun BlurImage(
modifier: Modifier = Modifier,
bitmap: Bitmap,
offset: IntOffset
) {
Canvas(modifier = modifier.fillMaxSize()) {
val blurBoxSize = 200.dp.toPx().toInt()
drawImage(
image = bitmap.asImageBitmap(),
srcOffset = offset,
srcSize = IntSize(blurBoxSize, blurBoxSize),
dstOffset = offset
)
}
}
@Suppress("DEPRECATION")
@Composable
private fun legacyBlurImage(
bitmap: Bitmap,
blurRadio: Float,
): Bitmap {
val currentBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true)
val renderScript = RenderScript.create(LocalContext.current)
val bitmapAlloc = Allocation.createFromBitmap(renderScript, currentBitmap)
ScriptIntrinsicBlur.create(renderScript, bitmapAlloc.element).apply {
setRadius(blurRadio)
setInput(bitmapAlloc)
forEach(bitmapAlloc)
}
bitmapAlloc.copyTo(currentBitmap)
renderScript.destroy()
return currentBitmap
}
private fun createBitmapFromPicture(picture: Picture): Bitmap {
val bitmap = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
Bitmap.createBitmap(picture)
} else {
val bitmap = Bitmap.createBitmap(
picture.width,
picture.height,
Bitmap.Config.ARGB_8888
)
val canvas = android.graphics.Canvas(bitmap)
canvas.drawColor(android.graphics.Color.WHITE)
canvas.drawPicture(picture)
bitmap
}
return bitmap
}
Image(
painter = painterResource (R.drawable.my_image)
modifier = Modifier
blur (radiusX = 15.dp, radiusY = 15.dp)
)
Scaffold(
modifier = Modifier
.fillMaxSize()
) {
Box(modifier = Modifier
.fillMaxSize()
.blur(10.dp)
){
AsyncImage(
modifier = Modifier.align(Alignment.Center).fillMaxSize(),
contentScale = ContentScale.FillBounds,
model =
"https://images.genius.com/225d6cb0fef34cc080a51fefb2384c8b.599x607x1.jpg",
contentDescription = "",
)
}
Column {//insert the rest of UI code here}
我曾经遇到过同样的问题,我试了这个方法,现在 Column 部分已经覆盖在 Box 上面。这应该会重叠在一起,给您一个模糊的背景。
如果我有任何错误,请告诉我。希望能帮到你!
编辑:很不幸,Modifier.blur() 不具备向后兼容性,因此它只适用于 Android 12 及以上版本的设备。