Jetpack Compose中的模糊效果

41
我该如何在Jetpack Compose中模糊背景或创建模糊覆盖层?目前没有任何文档或资源涉及此主题。简单来说,我希望能够本地实现类似这个的效果。
8个回答

67

这是一个已被要求的功能(仅在 Android 12 及以上版本中实现),您可能希望对其进行标记。
想法是创建一个模糊修饰符,它会像这样:

Modifier.blur(radius = 16.dp)

10
仅适用于 Android 12 及以上版本。 - Stanley
21
不适用于组合项的下层,因此无法创建模糊叠加效果。 它只允许对应用了修改器的组合项内的内容进行模糊处理。 - Ovi Trif

11
在Jetpack Compose:1.1.0-alpha03中,您可以使用:

Modifier.blur(30.dp)

但是仅在Android 12及以上版本中支持。试图在较旧的Android版本上使用此修饰符将被忽略。

参考文献Modifier.blur


1
这适用于 JetBrains Compose 在桌面上(我在这里使用 Linux),开箱即用。 - xdevs23

7

如果使用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"
)

5

6
虽然这个链接可能回答了问题,但最好在这里包含答案的基本部分并提供参考链接。仅有链接的答案如果链接页面发生变化则无效。- 来自审阅 - JustSightseeing
1
值得一提的是,此解决方案依赖于Android图形着色语言(AGSL),该语言在Android 13中引入(或者更具体地说是API 33)。https://developer.android.com/develop/ui/views/graphics/agsl - dbm

5


0
代码结果:Github仓库 高清版本

Bad quality cause 2MB limit

步骤:
- 将父可组合绘图重定向到Android Picture中。 您需要androidx.compose.ui:ui-graphics:1.6.0-alpha01 引用:
更新了DrawScope API,引入了将渲染重新定向到具有替代密度/布局方向和大小的不同画布的能力。
  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
}

0
只需像下面这样简单地使用蓝色修饰功能。
Image(
  painter = painterResource (R.drawable.my_image)
  modifier = Modifier
   blur (radiusX = 15.dp, radiusY = 15.dp)
)

-1
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 及以上版本的设备。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接