Размытие окна

В Android 12 доступны общедоступные API для реализации эффектов размытия окон, таких как размытие фона и размытие позади.

Размытие окон или размытие между окнами используется для размытия экрана за данным окном. Существует два типа размытия окон, которые можно использовать для достижения различных визуальных эффектов:

  • Размытие фона позволяет создавать окна с размытым фоном, создавая эффект матового стекла.

  • «Размытие сзади» позволяет размыть весь экран за (диалоговым) окном, создавая эффект глубины резкости.

Оба эффекта можно использовать по отдельности или вместе, как показано на следующем рисунке:

только размытие фона

а

размытие только позади

б

размытие сзади и размытие фона

с

Рисунок 1. Только размытие фона (а), только размытие сзади (б), размытие фона и размытие сзади (в)

Функция размытия окна работает во всех окнах, а это означает, что она также работает, когда за вашим окном находится другое приложение. Этот эффект отличается от эффекта размытия рендеринга , который размывает содержимое внутри того же окна. Размытие окон полезно для диалогов, нижних листов и других плавающих окон.

Выполнение

Разработчики приложений

Разработчики приложений должны указать радиус размытия, чтобы создать эффект размытия. Радиус размытия определяет плотность размытия: чем выше радиус, тем плотнее размытие. Размытие в 0 пикселей означает отсутствие размытия. Для размытия сзади радиус 20 пикселей создает хороший эффект глубины резкости, а радиус размытия фона 80 пикселей создает хороший эффект матового стекла. Избегайте радиусов размытия более 150 пикселей, поскольку это существенно повлияет на производительность.

Чтобы добиться желаемого эффекта размытия и повысить читаемость, выберите значение радиуса размытия, дополненное полупрозрачным слоем цвета.

Размытие фона

Используйте размытие фона в плавающих окнах, чтобы создать эффект фона окна, который представляет собой размытое изображение основного содержимого. Чтобы добавить размытый фон для вашего окна, сделайте следующее:

  1. Вызовите Window#setBackgroundBlurRadius(int), чтобы установить радиус размытия фона. Или в теме окна установите R.attr.windowBackgroundBlurRadius .

  2. Установите для R.attr.windowIsTranslucent значение true, чтобы сделать окно полупрозрачным. Размытие рисуется под поверхностью окна, поэтому окно должно быть полупрозрачным, чтобы размытие было видно.

  3. При необходимости вызовите Window#setBackgroundDrawableResource(int), чтобы добавить фон прямоугольного окна, который можно рисовать полупрозрачным цветом. Или в теме окна установите R.attr.windowBackground .

  4. Для окна с закругленными углами определите закругленные углы для размытой области, установив ShapeDrawable с закругленными углами в качестве рисуемого фона окна.

  5. Обработка включенных и отключенных состояний размытия. Дополнительную информацию см. в разделе «Рекомендации по использованию размытия окон в приложениях» .

Размытие позади

Размытие сзади размывает весь экран за окном. Этот эффект используется для направления внимания пользователя на содержимое окна путем размытия всего, что находится на экране за окном.

Чтобы размыть содержимое за окном, выполните следующие действия:

  1. Добавьте FLAG_BLUR_BEHIND к флажкам окна, чтобы включить размытие позади. Или в теме окна установите R.attr.windowBlurBehindEnabled .

  2. Вызовите WindowManager.LayoutParams#setBlurBehindRadius чтобы установить размытие за радиусом. Или в теме окна установите R.attr.windowBlurBehindRadius .

  3. При желании выберите дополняющее тусклое количество .

  4. Обработка включенных и отключенных состояний размытия. Дополнительную информацию см. в разделе «Рекомендации по использованию размытия окон в приложениях» .

Рекомендации по использованию размытия окон в приложениях

Поддержка размытия окон зависит от следующего:

  • Версия для Android: API-интерфейсы размытия Windows доступны только на Android 12 и более поздних версиях. Проверьте SDK устройства на предмет версии Android.

  • Производительность графики. Устройства с менее производительными графическими процессорами могут отказаться от поддержки размытия окон.

  • Состояние системы: системный сервер может временно отключить размытие окон во время выполнения, например, в режиме экономии заряда батареи, при воспроизведении определенных видов видеоконтента или по причине вмешательства разработчика.

Чтобы сделать ваше приложение совместимым с разными версиями Android, устройствами и состояниями системы, следуйте этим рекомендациям:

  • Добавьте прослушиватель через WindowManager#addCrossWindowBlurEnabledListener , чтобы уведомлять вас, когда размытие окон включено или отключено. Кроме того, используйте WindowManager#isCrossWindowBlurEnabled чтобы узнать, включено ли в данный момент размытие окон.

  • Реализуйте две версии фона окна, чтобы учесть включенное или отключенное состояние размытия окна.

    Если размытие включено, фон окна должен быть полупрозрачным, чтобы размытие было видно. В этом состоянии, когда размытие отключено, содержимое окна напрямую перекрывается с содержимым основного окна, что делает перекрывающееся окно менее разборчивым. Чтобы избежать такого эффекта, когда размытие окон отключено, адаптируйте пользовательский интерфейс приложения следующим образом:

    • Для размытия фона увеличьте альфу рисуемого фона окна, сделав его более непрозрачным.

    • Для размытия сзади добавьте затемненный слой с более высокой степенью затемнения.

Пример размытия позади и фона

В этом разделе представлен рабочий пример действия, в котором используется как размытие позади, так и размытие фона.

Следующий пример MainActivity.java представляет собой диалоговое окно с радиусом размытия задней части 20 пикселей и радиусом размытия фона 80 пикселей. Он имеет закругленные углы, определенные в xml на рисуемом фоне окна. Он правильно обрабатывает разные версии Android, разные устройства (которые потенциально не поддерживают размытие окон) и изменения, включенные или отключенные во время выполнения. Это гарантирует, что содержимое диалога будет читабельно при любом из этих условий, регулируя рисуемую альфу фона окна и степень затемнения окна.

public class MainActivity extends Activity {

    private final int mBackgroundBlurRadius = 80;
    private final int mBlurBehindRadius = 20;

    // We set a different dim amount depending on whether window blur is enabled or disabled
    private final float mDimAmountWithBlur = 0.1f;
    private final float mDimAmountNoBlur = 0.4f;

    // We set a different alpha depending on whether window blur is enabled or disabled
    private final int mWindowBackgroundAlphaWithBlur = 170;
    private final int mWindowBackgroundAlphaNoBlur = 255;

    // Use a rectangular shape drawable for the window background. The outline of this drawable
    // dictates the shape and rounded corners for the window background blur area.
    private Drawable mWindowBackgroundDrawable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWindowBackgroundDrawable = getDrawable(R.drawable.window_background);
        getWindow().setBackgroundDrawable(mWindowBackgroundDrawable);

        if (buildIsAtLeastS()) {
            // Enable blur behind. This can also be done in xml with R.attr#windowBlurBehindEnabled
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);

            // Register a listener to adjust window UI whenever window blurs are enabled/disabled
            setupWindowBlurListener();
        } else {
            // Window blurs are not available prior to Android S
            updateWindowForBlurs(false /* blursEnabled */);
        }

        // Enable dim. This can also be done in xml, see R.attr#backgroundDimEnabled
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    }

    /**
     * Set up a window blur listener.
     *
     * Window blurs might be disabled at runtime in response to user preferences or system states
     * (e.g. battery saving mode). WindowManager#addCrossWindowBlurEnabledListener allows to
     * listen for when that happens. In that callback we adjust the UI to account for the
     * added/missing window blurs.
     *
     * For the window background blur we adjust the window background drawable alpha:
     *     - lower when window blurs are enabled to make the blur visible through the window
     *       background drawable
     *     - higher when window blurs are disabled to ensure that the window contents are readable
     *
     * For window blur behind we adjust the dim amount:
     *     - higher when window blurs are disabled - the dim creates a depth of field effect,
     *       bringing the user's attention to the dialog window
     *     - lower when window blurs are enabled - no need for a high alpha, the blur behind is
     *       enough to create a depth of field effect
     */
    @RequiresApi(api = Build.VERSION_CODES.S)
    private void setupWindowBlurListener() {
        Consumer<Boolean> windowBlurEnabledListener = this::updateWindowForBlurs;
        getWindow().getDecorView().addOnAttachStateChangeListener(
                new View.OnAttachStateChangeListener() {
                    @Override
                    public void onViewAttachedToWindow(View v) {
                        getWindowManager().addCrossWindowBlurEnabledListener(
                                windowBlurEnabledListener);
                    }

                    @Override
                    public void onViewDetachedFromWindow(View v) {
                        getWindowManager().removeCrossWindowBlurEnabledListener(
                                windowBlurEnabledListener);
                    }
                });
    }

    private void updateWindowForBlurs(boolean blursEnabled) {
        mWindowBackgroundDrawable.setAlpha(blursEnabled && mBackgroundBlurRadius > 0 ?
                mWindowBackgroundAlphaWithBlur : mWindowBackgroundAlphaNoBlur);
        getWindow().setDimAmount(blursEnabled && mBlurBehindRadius > 0 ?
                mDimAmountWithBlur : mDimAmountNoBlur);

        if (buildIsAtLeastS()) {
            // Set the window background blur and blur behind radii
            getWindow().setBackgroundBlurRadius(mBackgroundBlurRadius);
            getWindow().getAttributes().setBlurBehindRadius(mBlurBehindRadius);
            getWindow().setAttributes(getWindow().getAttributes());
        }
    }

    private static boolean buildIsAtLeastS() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
    }
}

Чтобы создать закругленные углы окна, мы определяем фон окна в res/drawable/window_background.xml как ShapeDrawable с закругленными углами с радиусом 20 dp следующим образом:

<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
    <corners android:radius="20dp"/>
    <solid android:color="#AAAAAA"/>
</shape>

Размытие окна размывает содержимое окна под действием. Размытое изображение рисуется под этим окном активности, поэтому окно активности должно быть полупрозрачным, чтобы размытие было видно. Чтобы сделать окно полупрозрачным, мы устанавливаем R.attr.windowIsTranslucent в теме активности следующим образом:

<style name="Theme.BlurryDialog" parent="Theme.MaterialComponents.Dialog">
    <item name="android:windowIsTranslucent">true</item>
</style>

OEM-производители и партнеры

Чтобы использовать размытие окон на устройстве, OEM-производитель должен заявить, что устройство поддерживает размытие окон.

Чтобы проверить, поддерживает ли ваше устройство размытие окон, выполните следующие действия:

  • Убедитесь, что устройство может справиться с дополнительной нагрузкой на графический процессор. Устройства более низкого уровня могут не справиться с дополнительной нагрузкой, что может привести к потере кадров. Включайте размытие окон только на протестированных устройствах с достаточной мощностью графического процессора.

  • Если у вас есть настроенный механизм рендеринга, убедитесь, что он реализует логику размытия. Механизм рендеринга Android 12 по умолчанию реализует логику размытия в BlurFilter.cpp .

Убедившись, что ваше устройство поддерживает размытие окон, установите следующий sysprop Surface Flinger:

PRODUCT_VENDOR_PROPERTIES += \
       ro.surface_flinger.supports_background_blur=1

Валидация

Чтобы убедиться, что окно вашего приложения правильно обрабатывается при переключении между состояниями включения и отключения размытия, выполните следующие действия:

  1. Откройте пользовательский интерфейс с размытием.

  2. Включите или отключите размытие окон, включив и выключив размытие окон .

  3. Убедитесь, что пользовательский интерфейс окна меняется на размытое состояние, как и ожидалось.

Включение и выключение размытия окон

Чтобы проверить, как пользовательский интерфейс окна отображается с эффектом размытия окна, включите или отключите размытие одним из следующих методов:

  • Из опций разработчика:

    Настройки -> Система -> Параметры разработчика -> Аппаратное ускорение рендеринга -> Разрешить размытие на уровне окна.

  • Из терминала на корневом устройстве:

    adb shell wm disable-blur 1 # 1 disables window blurs, 0 allows them

Чтобы проверить, поддерживает ли ваше устройство Android 12+ размытие окон и включено ли размытие окон в данный момент, запустите adb shell wm disable-blur на корневом устройстве.

Поиск неисправностей

Используйте следующее в качестве руководства по устранению неполадок во время проверки.

Нет размытия

  • Убедитесь, что размытие в данный момент включено и ваше оборудование поддерживает его. См. раздел Включение и выключение размытия окон .

  • Убедитесь, что вы установили полупрозрачный цвет фона окна. Непрозрачный цвет фона окна скрывает размытую область.

Тестовое устройство не поддерживает размытие окон.

  • Проверьте свое приложение на эмуляторе Android 12. Чтобы настроить эмулятор Android, обратитесь к разделу «Настройка эмулятора Android» . Любое виртуальное устройство Android, созданное с помощью эмулятора, поддерживает размытие окон.

Никаких закругленных углов

Обновление опции разработчика не включает размытие

  • Проверьте, находится ли устройство в режиме экономии заряда батареи или использует туннелирование мультимедиа . На некоторых телевизионных устройствах размытие окон также может быть отключено во время воспроизведения видео.

Размытие фона нарисовано в полноэкранном режиме, за пределами границ окна.

  • Проверьте android:windowIsFloating , чтобы убедиться, что ваше окно помечено как плавающее.

  • Убедитесь, что установлен фоновый рисунок окна . Этот параметр определяет контур области размытия.

Обновления от прослушивателя не применяются на экране

  • Обновления прослушивателя могут быть применены к старому экземпляру окна. Проверьте, уничтожается ли окно и создается ли оно заново с помощью правильного обновления прослушивателя.
,

В Android 12 доступны общедоступные API для реализации эффектов размытия окон, таких как размытие фона и размытие позади.

Размытие окон или размытие между окнами используется для размытия экрана за данным окном. Существует два типа размытия окон, которые можно использовать для достижения различных визуальных эффектов:

  • Размытие фона позволяет создавать окна с размытым фоном, создавая эффект матового стекла.

  • «Размытие сзади» позволяет размыть весь экран за (диалоговым) окном, создавая эффект глубины резкости.

Оба эффекта можно использовать по отдельности или вместе, как показано на следующем рисунке:

только размытие фона

а

размытие только позади

б

размытие сзади и размытие фона

с

Рисунок 1. Только размытие фона (а), только размытие сзади (б), размытие фона и размытие сзади (в)

Функция размытия окна работает во всех окнах, а это означает, что она также работает, когда за вашим окном находится другое приложение. Этот эффект отличается от эффекта размытия рендеринга , который размывает содержимое внутри того же окна. Размытие окон полезно для диалогов, нижних листов и других плавающих окон.

Выполнение

Разработчики приложений

Разработчики приложений должны указать радиус размытия, чтобы создать эффект размытия. Радиус размытия определяет плотность размытия: чем выше радиус, тем плотнее размытие. Размытие в 0 пикселей означает отсутствие размытия. Для размытия сзади радиус 20 пикселей создает хороший эффект глубины резкости, а радиус размытия фона 80 пикселей создает хороший эффект матового стекла. Избегайте радиусов размытия более 150 пикселей, поскольку это существенно повлияет на производительность.

Чтобы добиться желаемого эффекта размытия и повысить читаемость, выберите значение радиуса размытия, дополненное полупрозрачным слоем цвета.

Размытие фона

Используйте размытие фона в плавающих окнах, чтобы создать эффект фона окна, который представляет собой размытое изображение основного содержимого. Чтобы добавить размытый фон для вашего окна, сделайте следующее:

  1. Вызовите Window#setBackgroundBlurRadius(int), чтобы установить радиус размытия фона. Или в теме окна установите R.attr.windowBackgroundBlurRadius .

  2. Установите для R.attr.windowIsTranslucent значение true, чтобы сделать окно полупрозрачным. Размытие рисуется под поверхностью окна, поэтому окно должно быть полупрозрачным, чтобы размытие было видно.

  3. При необходимости вызовите Window#setBackgroundDrawableResource(int), чтобы добавить фон прямоугольного окна, который можно рисовать полупрозрачным цветом. Или в теме окна установите R.attr.windowBackground .

  4. Для окна с закругленными углами определите закругленные углы для размытой области, установив ShapeDrawable с закругленными углами в качестве рисуемого фона окна.

  5. Обработка включенных и отключенных состояний размытия. Дополнительную информацию см. в разделе «Рекомендации по использованию размытия окон в приложениях» .

Размытие позади

Размытие сзади размывает весь экран за окном. Этот эффект используется для направления внимания пользователя на содержимое окна путем размытия всего, что находится на экране за окном.

Чтобы размыть содержимое за окном, выполните следующие действия:

  1. Добавьте FLAG_BLUR_BEHIND к флагам окна, чтобы включить размытие позади. Или в теме окна установите R.attr.windowBlurBehindEnabled .

  2. Вызовите WindowManager.LayoutParams#setBlurBehindRadius чтобы установить размытие за радиусом. Или в теме окна установите R.attr.windowBlurBehindRadius .

  3. При желании выберите дополняющее тусклое количество .

  4. Обработка включенных и отключенных состояний размытия. Дополнительную информацию см. в разделе «Рекомендации по использованию размытия окон в приложениях» .

Рекомендации по использованию размытия окон в приложениях

Поддержка размытия окон зависит от следующего:

  • Версия для Android: API-интерфейсы размытия Windows доступны только на Android 12 и более поздних версиях. Проверьте SDK устройства на предмет версии Android.

  • Производительность графики. Устройства с менее производительными графическими процессорами могут отказаться от поддержки размытия окон.

  • Состояние системы: системный сервер может временно отключить размытие окон во время выполнения, например, в режиме экономии заряда батареи, при воспроизведении определенных видов видеоконтента или из-за переопределения разработчика.

Чтобы сделать ваше приложение совместимым с разными версиями Android, устройствами и состояниями системы, следуйте этим рекомендациям:

  • Добавьте прослушиватель через WindowManager#addCrossWindowBlurEnabledListener , чтобы уведомлять вас, когда размытие окон включено или отключено. Кроме того, используйте WindowManager#isCrossWindowBlurEnabled чтобы узнать, включено ли в данный момент размытие окон.

  • Реализуйте две версии фона окна, чтобы учесть включенное или отключенное состояние размытия окна.

    Если размытие включено, фон окна должен быть полупрозрачным, чтобы размытие было видно. В этом состоянии, когда размытие отключено, содержимое окна напрямую перекрывается с содержимым основного окна, что делает перекрывающееся окно менее разборчивым. Чтобы избежать такого эффекта, когда размытие окон отключено, адаптируйте пользовательский интерфейс приложения следующим образом:

    • Для размытия фона увеличьте альфу рисуемого фона окна, сделав его более непрозрачным.

    • Для размытия сзади добавьте затемненный слой с более высокой степенью затемнения.

Пример размытия позади и фона

В этом разделе представлен рабочий пример действия, в котором используется как размытие позади, так и размытие фона.

Следующий пример MainActivity.java представляет собой диалоговое окно с радиусом размытия задней части 20 пикселей и радиусом размытия фона 80 пикселей. Он имеет закругленные углы, определенные в xml на рисуемом фоне окна. Он правильно обрабатывает разные версии Android, разные устройства (которые потенциально не поддерживают размытие окон) и изменения, включенные или отключенные во время выполнения. Это гарантирует, что содержимое диалога будет читаемо при любом из этих условий, регулируя рисуемую альфу фона окна и степень затемнения окна.

public class MainActivity extends Activity {

    private final int mBackgroundBlurRadius = 80;
    private final int mBlurBehindRadius = 20;

    // We set a different dim amount depending on whether window blur is enabled or disabled
    private final float mDimAmountWithBlur = 0.1f;
    private final float mDimAmountNoBlur = 0.4f;

    // We set a different alpha depending on whether window blur is enabled or disabled
    private final int mWindowBackgroundAlphaWithBlur = 170;
    private final int mWindowBackgroundAlphaNoBlur = 255;

    // Use a rectangular shape drawable for the window background. The outline of this drawable
    // dictates the shape and rounded corners for the window background blur area.
    private Drawable mWindowBackgroundDrawable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWindowBackgroundDrawable = getDrawable(R.drawable.window_background);
        getWindow().setBackgroundDrawable(mWindowBackgroundDrawable);

        if (buildIsAtLeastS()) {
            // Enable blur behind. This can also be done in xml with R.attr#windowBlurBehindEnabled
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);

            // Register a listener to adjust window UI whenever window blurs are enabled/disabled
            setupWindowBlurListener();
        } else {
            // Window blurs are not available prior to Android S
            updateWindowForBlurs(false /* blursEnabled */);
        }

        // Enable dim. This can also be done in xml, see R.attr#backgroundDimEnabled
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    }

    /**
     * Set up a window blur listener.
     *
     * Window blurs might be disabled at runtime in response to user preferences or system states
     * (e.g. battery saving mode). WindowManager#addCrossWindowBlurEnabledListener allows to
     * listen for when that happens. In that callback we adjust the UI to account for the
     * added/missing window blurs.
     *
     * For the window background blur we adjust the window background drawable alpha:
     *     - lower when window blurs are enabled to make the blur visible through the window
     *       background drawable
     *     - higher when window blurs are disabled to ensure that the window contents are readable
     *
     * For window blur behind we adjust the dim amount:
     *     - higher when window blurs are disabled - the dim creates a depth of field effect,
     *       bringing the user's attention to the dialog window
     *     - lower when window blurs are enabled - no need for a high alpha, the blur behind is
     *       enough to create a depth of field effect
     */
    @RequiresApi(api = Build.VERSION_CODES.S)
    private void setupWindowBlurListener() {
        Consumer<Boolean> windowBlurEnabledListener = this::updateWindowForBlurs;
        getWindow().getDecorView().addOnAttachStateChangeListener(
                new View.OnAttachStateChangeListener() {
                    @Override
                    public void onViewAttachedToWindow(View v) {
                        getWindowManager().addCrossWindowBlurEnabledListener(
                                windowBlurEnabledListener);
                    }

                    @Override
                    public void onViewDetachedFromWindow(View v) {
                        getWindowManager().removeCrossWindowBlurEnabledListener(
                                windowBlurEnabledListener);
                    }
                });
    }

    private void updateWindowForBlurs(boolean blursEnabled) {
        mWindowBackgroundDrawable.setAlpha(blursEnabled && mBackgroundBlurRadius > 0 ?
                mWindowBackgroundAlphaWithBlur : mWindowBackgroundAlphaNoBlur);
        getWindow().setDimAmount(blursEnabled && mBlurBehindRadius > 0 ?
                mDimAmountWithBlur : mDimAmountNoBlur);

        if (buildIsAtLeastS()) {
            // Set the window background blur and blur behind radii
            getWindow().setBackgroundBlurRadius(mBackgroundBlurRadius);
            getWindow().getAttributes().setBlurBehindRadius(mBlurBehindRadius);
            getWindow().setAttributes(getWindow().getAttributes());
        }
    }

    private static boolean buildIsAtLeastS() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
    }
}

Чтобы создать закругленные углы окна, мы определяем фон окна в res/drawable/window_background.xml как ShapeDrawable с закругленными углами с радиусом 20 dp следующим образом:

<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
    <corners android:radius="20dp"/>
    <solid android:color="#AAAAAA"/>
</shape>

Размытие окна размывает содержимое окна под действием. Размытое изображение рисуется под этим окном активности, поэтому окно активности должно быть полупрозрачным, чтобы размытие было видно. Чтобы сделать окно полупрозрачным, мы устанавливаем R.attr.windowIsTranslucent в теме активности следующим образом:

<style name="Theme.BlurryDialog" parent="Theme.MaterialComponents.Dialog">
    <item name="android:windowIsTranslucent">true</item>
</style>

OEM-производители и партнеры

Чтобы размывать окно на устройстве, OEM должен заявить, что устройство поддерживает размытые окна.

Чтобы проверить, поддерживает ли ваше устройство размытие окон, выполните следующие действия:

  • Убедитесь, что устройство может справиться с дополнительной нагрузкой на графический процессор. Устройства более низкого уровня могут не справиться с дополнительной нагрузкой, что может привести к потере кадров. Включайте размытие окон только на протестированных устройствах с достаточной мощностью графического процессора.

  • Если у вас есть настроенный механизм рендеринга, убедитесь, что он реализует логику размытия. Механизм рендеринга Android 12 по умолчанию реализует логику размытия в BlurFilter.cpp .

Убедившись, что ваше устройство поддерживает размытие окон, установите следующий sysprop Surface Flinger:

PRODUCT_VENDOR_PROPERTIES += \
       ro.surface_flinger.supports_background_blur=1

Валидация

Чтобы убедиться, что окно вашего приложения правильно обрабатывается при переключении между состояниями включения и отключения размытия, выполните следующие действия:

  1. Откройте пользовательский интерфейс с размытием.

  2. Включите или отключите размытие окон, включив и выключив размытие окон .

  3. Убедитесь, что пользовательский интерфейс окна меняется на размытое состояние, как и ожидалось.

Включение и выключение размытия окон

Чтобы проверить, как пользовательский интерфейс окна отображается с эффектом размытия окна, включите или отключите размытие одним из следующих методов:

  • Из опций разработчика:

    Настройки -> Система -> Параметры разработчика -> Аппаратное ускорение рендеринга -> Разрешить размытие на уровне окна.

  • Из терминала на корневом устройстве:

    adb shell wm disable-blur 1 # 1 disables window blurs, 0 allows them

Чтобы проверить, поддерживает ли ваше устройство Android 12+ размытие окон и включено ли размытие окон в данный момент, запустите adb shell wm disable-blur на корневом устройстве.

Поиск неисправностей

Используйте следующее в качестве руководства по устранению неполадок во время проверки.

Нет размытия

  • Убедитесь, что размытие в данный момент включено и ваше оборудование поддерживает его. См. раздел Включение и выключение размытия окон .

  • Убедитесь, что вы установили полупрозрачный цвет фона окна. Непрозрачный цвет фона окна скрывает размытую область.

Тестовое устройство не поддерживает размытие окон.

  • Проверьте свое приложение на эмуляторе Android 12. Чтобы настроить эмулятор Android, обратитесь к разделу «Настройка эмулятора Android» . Любое виртуальное устройство Android, созданное с помощью эмулятора, поддерживает размытие окон.

Никаких закругленных углов

Обновление опции разработчика не включает размытие

  • Проверьте, находится ли устройство в режиме экономии заряда батареи или использует туннелирование мультимедиа . На некоторых телевизионных устройствах размытие окон также может быть отключено во время воспроизведения видео.

Размытие фона нарисовано в полноэкранном режиме, за пределами границ окна.

  • Проверьте android:windowIsFloating , чтобы убедиться, что ваше окно помечено как плавающее.

  • Убедитесь, что установлен фоновый рисунок окна . Этот параметр определяет контур области размытия.

Обновления от прослушивателя не применяются на экране

  • Обновления прослушивателя могут быть применены к старому экземпляру окна. Проверьте, уничтожается ли окно и создается ли оно заново с помощью правильного обновления прослушивателя.
,

В Android 12 доступны общедоступные API для реализации эффектов размытия окон, таких как размытие фона и размытие позади.

Размытие окон или размытие между окнами используется для размытия экрана за данным окном. Существует два типа размытия окон, которые можно использовать для достижения различных визуальных эффектов:

  • Размытие фона позволяет создавать окна с размытым фоном, создавая эффект матового стекла.

  • Размытие позади позволяет размыть весь экран за окном (диалоговое окно, создавая эффект глубины поля.

Оба эффекта можно использовать по отдельности или вместе, как показано на следующем рисунке:

только размытие фона

а

размытие только позади

б

размытие сзади и размытие фона

с

Рисунок 1. Только размытие фона (а), только размытие сзади (б), размытие фона и размытие сзади (в)

Функция размытия окна работает во всех окнах, а это означает, что она также работает, когда за вашим окном находится другое приложение. Этот эффект отличается от эффекта размытия рендеринга , который размывает содержимое внутри того же окна. Размытие окон полезно для диалогов, нижних листов и других плавающих окон.

Выполнение

Разработчики приложений

Разработчики приложений должны указать радиус размытия, чтобы создать эффект размытия. Радиус размытия определяет плотность размытия: чем выше радиус, тем плотнее размытие. Размытие в 0 пикселей означает отсутствие размытия. Для размытия сзади радиус 20 пикселей создает хороший эффект глубины резкости, а радиус размытия фона 80 пикселей создает хороший эффект матового стекла. Избегайте радиусов размытия более 150 пикселей, поскольку это существенно повлияет на производительность.

Чтобы добиться желаемого эффекта размытия и повысить читаемость, выберите значение радиуса размытия, дополненное полупрозрачным слоем цвета.

Размытие фона

Используйте размытие фона в плавающих окнах, чтобы создать эффект фона окна, который представляет собой размытое изображение основного содержимого. Чтобы добавить размытый фон для вашего окна, сделайте следующее:

  1. Звоните в окно#setbackgroundblurradius (int), чтобы установить радиус размытия. Или в теме окна установите R.attr.windowBackgroundBlurRadius .

  2. Установите для R.attr.windowIsTranslucent значение true, чтобы сделать окно полупрозрачным. Размытие рисуется под поверхностью окна, поэтому окно должно быть полупрозрачным, чтобы размытие было видно.

  3. При необходимости вызовите Window#setBackgroundDrawableResource(int), чтобы добавить фон прямоугольного окна, который можно рисовать полупрозрачным цветом. Или в теме окна установите R.attr.windowBackground .

  4. Для окна с закругленными углами определите закругленные углы для размытой области, установив ShapeDrawable с закругленными углами в качестве рисуемого фона окна.

  5. Обработка включенных и отключенных состояний размытия. Дополнительную информацию см. в разделе «Рекомендации по использованию размытия окон в приложениях» .

Размытие позади

Размытие сзади размывает весь экран за окном. Этот эффект используется для направления внимания пользователя на содержимое окна путем размытия всего, что находится на экране за окном.

Чтобы размыть содержимое за окном, выполните следующие действия:

  1. Добавьте FLAG_BLUR_BEHIND к флажкам окна, чтобы включить размытие позади. Или в теме окна установите R.attr.windowBlurBehindEnabled .

  2. Вызовите WindowManager.LayoutParams#setBlurBehindRadius чтобы установить размытие за радиусом. Или, в тему окна, установите r.attr.windowblurbehindradius .

  3. При желании выберите дополняющее тусклое количество .

  4. Обработка включенных и отключенных состояний размытия. Обратитесь к руководящим принципам для использования размытия Window в разделе «Приложения» для получения дополнительной информации.

Рекомендации по использованию размытия окон в приложениях

Поддержка Windows Blur зависит от следующего:

  • Версия Android: API Windows Blur доступны только на Android 12 и выше. Проверьте SDK устройства на предмет версии Android.

  • Производительность графика: устройства с менее производительными графическими процессорами могут не поддерживать витрины.

  • Состояние системы: системный сервер может временно отключить размытие окон во время выполнения, например, в режиме экономии заряда батареи, при воспроизведении определенных видов видеоконтента или из-за переопределения разработчика.

Чтобы сделать ваше приложение совместимым между версиями Android, устройствами и системами системы, следуйте этим рекомендациям:

  • Добавьте слушатель через Windowmanager#addcrosswindowblurenabledListener , чтобы уведомить вас, когда размыты в окне включены или отключены. Кроме того, используйте WindowManager#isCrossWindowBlurEnabled чтобы запросить, включены ли в данный момент разблокировки окон.

  • Реализуйте две версии для фона окна, чтобы приспособиться к включенному или отключенному состоянию окна.

    При включении блуд, фон окна должен быть полупрозрачным, чтобы сделать размытие видимым. В этом состоянии, когда размытие отключено, содержимое окна напрямую перекрывается с содержимым основного окна, что делает перекрывающееся окно менее разборчивым. Чтобы избежать такого эффекта, при отключении окна отключены, адаптируйте пользовательский интерфейс приложения следующим образом:

    • Для размытия фона увеличьте альфу рисуемого фона окна, сделав его более непрозрачным.

    • Для размытия сзади добавьте затемненный слой с более высокой степенью затемнения.

Пример размытия позади и фона

В этом разделе представлен рабочий пример действия, в котором используется как размытие позади, так и размытие фона.

Следующий пример MainActivity.java представляет собой диалоговое окно с радиусом размытия задней части 20 пикселей и радиусом размытия фона 80 пикселей. Он имеет закругленные углы, определенные в xml на рисуемом фоне окна. Он правильно обрабатывает разные версии Android, разные устройства (которые потенциально не поддерживают размытие окон) и изменения, включенные или отключенные во время выполнения. Это гарантирует, что содержимое диалога будет читаемо при любом из этих условий, регулируя рисуемую альфу фона окна и степень затемнения окна.

public class MainActivity extends Activity {

    private final int mBackgroundBlurRadius = 80;
    private final int mBlurBehindRadius = 20;

    // We set a different dim amount depending on whether window blur is enabled or disabled
    private final float mDimAmountWithBlur = 0.1f;
    private final float mDimAmountNoBlur = 0.4f;

    // We set a different alpha depending on whether window blur is enabled or disabled
    private final int mWindowBackgroundAlphaWithBlur = 170;
    private final int mWindowBackgroundAlphaNoBlur = 255;

    // Use a rectangular shape drawable for the window background. The outline of this drawable
    // dictates the shape and rounded corners for the window background blur area.
    private Drawable mWindowBackgroundDrawable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWindowBackgroundDrawable = getDrawable(R.drawable.window_background);
        getWindow().setBackgroundDrawable(mWindowBackgroundDrawable);

        if (buildIsAtLeastS()) {
            // Enable blur behind. This can also be done in xml with R.attr#windowBlurBehindEnabled
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);

            // Register a listener to adjust window UI whenever window blurs are enabled/disabled
            setupWindowBlurListener();
        } else {
            // Window blurs are not available prior to Android S
            updateWindowForBlurs(false /* blursEnabled */);
        }

        // Enable dim. This can also be done in xml, see R.attr#backgroundDimEnabled
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    }

    /**
     * Set up a window blur listener.
     *
     * Window blurs might be disabled at runtime in response to user preferences or system states
     * (e.g. battery saving mode). WindowManager#addCrossWindowBlurEnabledListener allows to
     * listen for when that happens. In that callback we adjust the UI to account for the
     * added/missing window blurs.
     *
     * For the window background blur we adjust the window background drawable alpha:
     *     - lower when window blurs are enabled to make the blur visible through the window
     *       background drawable
     *     - higher when window blurs are disabled to ensure that the window contents are readable
     *
     * For window blur behind we adjust the dim amount:
     *     - higher when window blurs are disabled - the dim creates a depth of field effect,
     *       bringing the user's attention to the dialog window
     *     - lower when window blurs are enabled - no need for a high alpha, the blur behind is
     *       enough to create a depth of field effect
     */
    @RequiresApi(api = Build.VERSION_CODES.S)
    private void setupWindowBlurListener() {
        Consumer<Boolean> windowBlurEnabledListener = this::updateWindowForBlurs;
        getWindow().getDecorView().addOnAttachStateChangeListener(
                new View.OnAttachStateChangeListener() {
                    @Override
                    public void onViewAttachedToWindow(View v) {
                        getWindowManager().addCrossWindowBlurEnabledListener(
                                windowBlurEnabledListener);
                    }

                    @Override
                    public void onViewDetachedFromWindow(View v) {
                        getWindowManager().removeCrossWindowBlurEnabledListener(
                                windowBlurEnabledListener);
                    }
                });
    }

    private void updateWindowForBlurs(boolean blursEnabled) {
        mWindowBackgroundDrawable.setAlpha(blursEnabled && mBackgroundBlurRadius > 0 ?
                mWindowBackgroundAlphaWithBlur : mWindowBackgroundAlphaNoBlur);
        getWindow().setDimAmount(blursEnabled && mBlurBehindRadius > 0 ?
                mDimAmountWithBlur : mDimAmountNoBlur);

        if (buildIsAtLeastS()) {
            // Set the window background blur and blur behind radii
            getWindow().setBackgroundBlurRadius(mBackgroundBlurRadius);
            getWindow().getAttributes().setBlurBehindRadius(mBlurBehindRadius);
            getWindow().setAttributes(getWindow().getAttributes());
        }
    }

    private static boolean buildIsAtLeastS() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
    }
}

Чтобы создать закругленные углы окна, мы определяем фон окна в res/drawable/window_background.xml как ShapeDrawable с закругленными углами с радиусом 20 dp следующим образом:

<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
    <corners android:radius="20dp"/>
    <solid android:color="#AAAAAA"/>
</shape>

Размытие окна размывает содержимое окна под действием. Размытое изображение рисуется под этим окном активности, поэтому окно активности должно быть полупрозрачным, чтобы размытие было видно. Чтобы сделать окно полупрозрачным, мы устанавливаем R.attr.windowIsTranslucent в теме активности следующим образом:

<style name="Theme.BlurryDialog" parent="Theme.MaterialComponents.Dialog">
    <item name="android:windowIsTranslucent">true</item>
</style>

OEM-производители и партнеры

Чтобы использовать размытие окон на устройстве, OEM-производитель должен заявить, что устройство поддерживает размытие окон.

Чтобы проверить, может ли ваше устройство поддерживать размытые окна, сделайте следующее:

  • Убедитесь, что устройство может обрабатывать дополнительную нагрузку GPU. Устройства более низкого класса могут не иметь возможности обрабатывать дополнительную нагрузку, которая может вызвать падение рамки. Включите только промывки окна на тестируемых устройствах с достаточной мощностью графического процессора.

  • Если у вас есть индивидуальный двигатель рендеринга, убедитесь, что ваш двигатель рендеринга реализует размывающуюся логику. Двигатель Android 12 по умолчанию 12 реализует логику размытия в BlurFilter.cpp .

После того, как вы убедитесь, что ваше устройство может поддерживать размытые окна, установите следующую поверхность Flinger sysprop :

PRODUCT_VENDOR_PROPERTIES += \
       ro.surface_flinger.supports_background_blur=1

Валидация

Чтобы подтвердить, что окно вашего приложения имеет надлежащую обработку при переключении между размыванием и состояниями отключения размытия, выполните следующие действия:

  1. Откройте пользовательский интерфейс с размытием.

  2. Включите или отключите размытие окна, включив и выключает окно .

  3. Убедитесь, что пользовательский интерфейс окна меняется на размытое состояние, как и ожидалось.

Включение и выключение размытия окон

Чтобы проверить, как пользовательский интерфейс окна отображается с эффектом размытия окна, включите или отключите размытие одним из следующих методов:

  • Из опций разработчика:

    Настройки -> Система -> Параметры разработчика -> Аппаратное ускорение рендеринга -> Разрешить размытие на уровне окна.

  • Из терминала на корневом устройстве:

    adb shell wm disable-blur 1 # 1 disables window blurs, 0 allows them

Чтобы проверить, поддерживает ли ваше устройство Android 12+ размытие окон и включено ли размытие окон в данный момент, запустите adb shell wm disable-blur на корневом устройстве.

Поиск неисправностей

Используйте следующее в качестве руководства по устранению неполадок во время проверки.

Нет размытия

  • Убедитесь, что размытие в данный момент включено и ваше оборудование поддерживает его. См. раздел Включение и выключение размытия окон .

  • Убедитесь, что вы установили полупрозрачный цвет фона окна. Непрозрачный цвет фона окна скрывает размытую область.

Тестовое устройство не поддерживает размытие окон.

  • Проверьте свое приложение на эмуляторе Android 12. Чтобы настроить эмулятор Android, обратитесь к разделу «Настройка эмулятора Android» . Любое виртуальное устройство Android, созданное с помощью эмулятора, поддерживает размытие окон.

Никаких закругленных углов

Обновление опции разработчика не включает размытие

  • Проверьте, находится ли устройство в режиме экономии заряда батареи или использует туннелирование мультимедиа . На некоторых телевизионных устройствах размытие окон также может быть отключено во время воспроизведения видео.

Размытие фона нарисовано в полноэкранном режиме, за пределами границ окна.

  • Проверьте android:windowIsFloating , чтобы убедиться, что ваше окно помечено как плавающее.

  • Убедитесь, что установлен фоновый рисунок окна . Этот параметр определяет контур области размытия.

Обновления от прослушивателя не применяются на экране

  • Обновления прослушивателя могут быть применены к старому экземпляру окна. Проверьте, уничтожается ли окно и создается ли оно заново с помощью правильного обновления прослушивателя.