在 Android 12 中,公共 API 可用于实现窗口模糊效果(例如背景模糊和背后模糊)。请注意,尽管您可能会在代码、开发人员文档或 UI 表示法中看到窗口模糊也称为交叉窗口模糊,但交叉窗口模糊与窗口模糊相同。
使用这些 API,您可以模糊自己窗口后面的任何内容。您可以创建背景模糊的窗口,创建磨砂玻璃效果,或显示窗口,使其后面的整个屏幕模糊,创建景深效果。您也可以将这两种效果结合起来。
1 | 2 | 3 |
图 1. Background blur only (1), blur only behind (2), background blur and blur behind (3)
窗口模糊功能适用于整个窗口,这意味着当您正在查看的窗口后面有另一个应用程序时,它也可以工作。这与模糊渲染效果不同,后者会模糊同一应用程序中窗口内的内容。窗口模糊对于对话框和底部工作表以及其他浮动窗口很有用。
请务必注意,此功能使用大量 GPU 资源。因此,尽管它适用于所有 Android 设备,但仅支持那些具有足够 GPU 能力的设备。
执行
原始设备制造商和合作伙伴
默认情况下禁用窗口模糊。要在设备上启用模糊功能,请执行以下操作:
- 确保设备可以处理额外的 GPU 负载 - 模糊操作很昂贵,并且在低端设备上,它可能会导致丢帧。仅在具有足够 GPU 能力的设备上启用此功能。
- 确保您的
librenderengine
实现了模糊逻辑 - 默认的 Android 12 渲染引擎会这样做,但任何自定义渲染引擎都必须自己实现模糊逻辑。 - 通过设置以下surface flinger sysprop来启用模糊:
# enable surface flinger window blurs
PRODUCT_PROPERTY_OVERRIDES += \
ro.surface_flinger.supports_background_blur=1
第三方开发商
请参阅示例和源代码部分以查看示例代码。系统服务器可以在运行时禁用窗口模糊。因此,应用程序必须提供一个后备的、无模糊的版本。否则,如果模糊因为被禁用而未渲染,则窗口背景可能非常透明,以至于窗口内的内容变得难以辨认。如果您的应用不提供后备应用版本,请确保您的 UI 在启用模糊和禁用模糊的情况下都能正常工作。以下是可以随时禁用模糊的三种情况:
- 该设备运行的是 Android 11 或更低版本。由于窗口模糊仅在 Android 12 及更高版本的设备上可用,因此应用必须为运行 Android 11 及更低版本的设备实现备用的模糊体验替代方案。
- 该设备不支持窗口模糊,因为它们很昂贵,因此低端设备在渲染它们时可能会丢帧。对于这种情况,应用程序必须提供回退的模糊体验。
- 系统服务器(例如,在省电模式期间,或由于开发人员设置或隧道模式)在运行时禁用模糊。
上面的第2点和第 3点都由使用WindowManager.addCrossWindowBlurEnabledListener注册的侦听器报告。如果您的应用程序使用模糊 API,请注册此侦听器并在调用该侦听器时更新您的 UI,如果您想为启用模糊和禁用模糊状态使用不同的 UI。注册后,立即调用侦听器以报告当前是否启用了模糊。
使用以下方法实现模糊功能:
背景模糊:
setBackgroundBlurRadius
方法。您还必须确保窗口是半透明的:将
windowIsTranslucent
设置为true
并使用setBackgroundDrawable
创建具有半透明颜色的窗口背景。 (您也可以选择圆角。)模糊背后:
setBlurBehindRadius
模糊侦听器入口点:
addCrossWindowBlurEnabledListener
。方便模糊启用 getter:
isCrossWindowBlurEnabled
。
示例和来源
public class BlurActivity extends Activity {
private final int mBackgroundBlurRadius = 150;
private final Drawable mBackgroundDrawableWithBlur;
private final Drawable mBackgroundDrawableNoBlur;
private final int mBlurBehindRadius = 50;
private final float mDimAmountWithBlur = 0.1f;
private final float mDimAmountNoBlur = 0.6f;
private Consumer<Boolean> mCrossWindowBlurEnabledListener = enabled -> {
getWindow().setBackgroundDrawable(
enabled ? mBackgroundDrawableWithBlur : mBackgroundDrawableNoBlur);
getWindow().setDimAmount(enabled ? mDimAmountWithBlur : mDimAmountNoBlur);
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.blur_activity);
mBackgroundDrawableWithBlur = getContext().getResources().getDrawable(
R.drawable.window_background_with_blur);
mBackgroundDrawableNoBlur = getContext().getResources().getDrawable(
R.drawable.window_background_no_blur);
if (Android version >= Android S) {
getWindow().addFlags(
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
window.getAttributes().setBlurBehindRadius(mBlurBehindRadius);
window.setBackgroundBlurRadius(mBackgroundBlurRadius);
getWindow().getDecorView().addOnAttachStateChangeListener(
new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
getWindowManager().addCrossWindowBlurEnabledListener(
blurEnabledListener);
}
@Override
public void onViewDetachedFromWindow(View v) {
getWindowManager().removeCrossWindowBlurEnabledListener(
blurEnabledListener);
}
});
}
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
}
打开和关闭窗口模糊
有两种方法可以允许和禁止窗口模糊。
从用户界面:
设置 -> 系统 -> 开发者选项 -> 硬件加速渲染 -> 允许窗口级模糊
从终端(设备必须植根):
adb shell wm disable-blur 1 # 1 disables window blurs, 0 allows them
如果您的设备能够支持模糊,您只能打开或关闭窗口模糊功能。 (不支持窗口模糊的设备无法启用该功能。)默认情况下,在支持它们的设备上启用模糊。
当您为设备启用模糊时,请考虑诸如省电模式或多媒体隧道之类的其他功能可以禁用它们。当满足所有必要条件时启用模糊 - 它们受到支持,并且没有任何东西禁用它们。要查看模糊功能的当前状态是否为“启用”,请使用adb shell wm disable-blur
命令。
验证
为确保您的模糊功能版本按预期工作,请实现 UI 逻辑,以便在blurEnabled
更改时重绘 UI 元素(如addCrossWindowBlurEnabledListener
报告的那样)。
- 打开有模糊的 UI。
- 使用从 UI 或 CLI打开和关闭窗口模糊给出的步骤。
- 验证 UI 是否按预期更改为模糊的。
故障排除
使用以下内容作为验证期间故障排除的指南。
没有画模糊
通过使用 CLI 或导航到Settings来验证当前是否启用了模糊(并且您的硬件支持它们)。
- 使用
adb shell wm disable-blur
命令,该命令会打印出该设备是否支持模糊以及当前是否启用。 - 导航到设置 -> 系统 -> 开发人员选项 -> 硬件加速渲染 -> 允许窗口级模糊。如果您在此处找不到该选项,则您的设备不支持模糊。
- 使用
确保设置半透明的窗口背景颜色;不透明的窗口背景颜色隐藏(覆盖)模糊区域。
测试设备不支持窗口模糊
- 在 Android 12 模拟器上测试您的应用程序。要设置 Android 模拟器,请参阅设置 Android 模拟器说明。您使用模拟器创建的任何 Android 虚拟设备都将支持窗口模糊。
没有圆角
- 通过设置窗口背景可绘制对象 -
Window#setBackgroundDrawable
来定义圆角。这决定了模糊区域的轮廓。
更新开发者选项不会启用模糊
- 检查设备是否处于省电模式,是否使用多媒体隧道(用于电视),或者是否有其他原因禁用模糊功能。
背景模糊绘制全屏,不在窗口范围内
- 确保您的窗口被标记为浮动 -
android:windowIsFloating
- 确保您已设置窗口背景可绘制对象 -
Window#setBackgroundDrawable
。这决定了模糊区域的轮廓。
来自监听器的更新不会应用到屏幕上
- 检查窗口是否被销毁并重新创建,而侦听器正在操作的实例没有更新。侦听器更新可能会应用于旧窗口实例。