在 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
。這決定了模糊區域的輪廓。
來自監聽器的更新不會應用到屏幕上
- 檢查窗口是否被銷毀並重新創建,而偵聽器正在操作的實例沒有更新。偵聽器更新可能會應用於舊窗口實例。