Android窗口背景模糊

248 阅读2分钟

官方指导:source.android.google.cn/docs/core/d…

样例代码:github.com/OkieLe/Wind…

注意:仅支持Android 12及以上平台

1. 使用方法

1.1 模糊当前窗口背景

image.png

  • 设置窗口半透明:主题中 windowIsTranslucent 设置为 true
  • 设置模糊半径:主题中 backgroundBlurRadius 设置为非0,Window 也有相应方法 setBackgroundBlurRadius
    • 取值范围(0, 150)
    • 典型数值 20 即可达到一般模糊效果,80可达到高斯模糊效果
    • 数值越大,性能越差
  • 设置窗口背景透明:主题或者代码中设置 windowBackground 为带透明度的颜色或者Drawable
    • 通过带圆角和透明度的 ShapeDrawable 可以支持带圆角的窗口

1.2 模糊当前窗口后面整个屏幕

image.png

  • 使能模糊:主题中 windowBlurBehindEnabled 设置为 true 或 窗口添加 FLAG_BLUR_BEHIND
  • 设置模糊半径:主题中 windowBlurBehindRadius 设置为非0,Window.LayoutParams 也有相应方法 setBlurBehindRadius
    • 取值范围(0, 150)
    • 典型数值 20 即可达到一般模糊效果,80可达到高斯模糊效果
    • 数值越大,性能越差
  • 还可以设置背景屏幕变暗(可选):
    • 使能背景变暗:主题中 backgroundDimEnabled 设置为 true 或窗口添加 FLAG_DIM_BEHIND
    • 设置变暗程度:主题中 dimAmount 设置为 0 - 1 的浮点数,越大越不透明,Window 也有相应方法 setDimAmount
  • 显示出被窗口覆盖区域的内容(可选):主题中 windowIsTranslucent 设置为 true,使窗口半透明
    • 设置透明窗口背景:主题或者代码中设置 windowBackground 为带透明度的颜色或者Drawable

以上两种方式可以同时使用

1.3 监听窗口模糊开关变化

窗口模糊在运行时可能会被禁用,比如用户操作或者省电模式,可以通过 WindowManager 中的接口监听变化和查看状态

// Add listener
void addCrossWindowBlurEnabledListener(Consumer<Boolean> listener)
// Remove listener
void removeCrossWindowBlurEnabledListener(Consumer<Boolean> listener)
// Get the blur enable state
boolean isCrossWindowBlurEnabled()

2. 模糊实现机制简介

基于Android 14 源码

2.1 模糊当前窗口背景

实现主要分为两部分:设置参数和图像合成,图像合成单列出来说明 设置参数主要涉及到的类:

  • PhoneWindow
  • DecorView
  • BackgroundBlurDrawable
  • ViewRootImpl
  • SurfaceControl
  • SurfaceComposeClient
  • SurfaceFlinger

image.png

2.2 模糊当前窗口后面整个屏幕

实现主要分为两部分:设置参数和图像合成,图像合成单列出来说明 设置参数主要涉及到的类:

  • WindowManagerService
  • WindowState
  • Dimmer
  • SurfaceControl
  • SurfaceComposeClient
  • SurfaceFlinger

image.png

2.3 图像合成

前面 2.1/2.2 分别将blur相关信息传到SurfaceFlinger,在下一帧图像合成时就会包含模糊图形 合成主要涉及的类:

  • SurfaceFlinger
  • CompositionEngine
  • Display/Output
  • RenderEngine
  • SkiaRenderEngine
  • BlurFilter

image.png

drawLayersInternal 中会从后往前将每一个需要合成的 Layer 绘制到Buffer中,模糊相关的请搜索 BlurFilter