Weichzeichnen von Fenstern

In Android 12 sind öffentliche APIs verfügbar, mit denen sich Fensterunschärfeeffekte wie Hintergrundunschärfe und Unschärfe hinter dem Fenster implementieren lassen.

Fensterunschärfen oder fensterübergreifende Unschärfen werden verwendet, um den Bildschirm hinter dem jeweiligen Fenster unscharf zu machen. Es gibt zwei Arten von Fensterunschärfen, mit denen sich unterschiedliche visuelle Effekte erzielen lassen:

  • Mit Hintergrundunschärfe können Sie Fenster mit unscharfem Hintergrund erstellen, um einen Milchglaseffekt zu erzielen.

  • Mit Hintergrund weichzeichnen können Sie den gesamten Bildschirm hinter einem (Dialog-)Fenster weichzeichnen und so einen Tiefenschärfeeffekt erzeugen.

Die beiden Effekte können separat oder kombiniert verwendet werden, wie in der folgenden Abbildung gezeigt:

nur weichgezeichneter Hintergrund

a

nur hinter dem Motiv weichzeichnen

b

Weichzeichnen hinter dem Motiv und Hintergrund weichzeichnen

c

Abbildung 1. Nur Hintergrund weichzeichnen (a), nur Hintergrund weichzeichnen (b), Hintergrund weichzeichnen und Hintergrund weichzeichnen (c)

Die Funktion „Fensterunschärfe“ funktioniert fensterübergreifend, d. h. auch dann, wenn sich hinter dem Fenster eine andere App befindet. Dieser Effekt ist nicht mit dem Weichzeichner-Rendering-Effekt zu verwechseln, der den Inhalt innerhalb desselben Fensters weichzeichnet. Fensterunschärfen sind nützlich für Dialogfelder, Ansichten am unteren Rand und andere unverankerte Fenster.

Implementierung

App-Entwickler

App-Entwickler müssen einen Unschärferadius angeben, um einen Unschärfeeffekt zu erstellen. Der Unschärferadius bestimmt, wie dicht die Unschärfe ist. Je höher der Radius, desto dichter die Unschärfe. Ein Wert von 0 px bedeutet, dass keine Unschärfe angewendet wird. Für die Unschärfe im Hintergrund erzeugt ein Radius von 20 px einen guten Tiefenschärfeeffekt, während ein Radius von 80 px für die Hintergrundunschärfe einen guten Milchglaseffekt erzeugt. Vermeiden Sie Unschärferadien von mehr als 150 Pixeln, da dies die Leistung erheblich beeinträchtigt.

Um den gewünschten Unschärfeeffekt zu erzielen und die Lesbarkeit zu verbessern, wählen Sie einen Wert für den Unschärferadius aus, der durch eine durchscheinende Farbschicht ergänzt wird.

Weichgezeichneter Hintergrund

Verwenden Sie die Hintergrundunschärfe für schwebende Fenster, um einen Fensterhintergrundeffekt zu erstellen, der ein unscharfes Bild des zugrunde liegenden Inhalts ist. So fügen Sie Ihrem Fenster einen weichgezeichneten Hintergrund hinzu:

  1. Rufe Window#setBackgroundBlurRadius(int) auf, um einen Radius für die Hintergrundunschärfe festzulegen. Alternativ können Sie im Fensterdesign R.attr.windowBackgroundBlurRadius festlegen.

  2. Setze R.attr.windowIsTranslucent auf „true“, um das Fenster durchscheinend zu machen. Die Unschärfe wird unter der Fensteroberfläche gezeichnet. Das Fenster muss also durchscheinend sein, damit die Unschärfe sichtbar ist.

  3. Optional kannst du Window#setBackgroundDrawableResource(int) aufrufen, um ein rechteckiges Fensterhintergrund-Drawable mit einer durchscheinenden Farbe hinzuzufügen. Alternativ kannst du im Fensterdesign R.attr.windowBackground festlegen.

  4. Bei einem Fenster mit abgerundeten Ecken können Sie die abgerundeten Ecken für den weichgezeichneten Bereich festlegen, indem Sie ein ShapeDrawable mit abgerundeten Ecken als Drawable für den Fensterhintergrund festlegen.

  5. Aktivierte und deaktivierte Zustände für die Unschärfe verarbeiten. Weitere Informationen findest du im Abschnitt Richtlinien für die Verwendung von Fensterunschärfe in Apps.

Hintergrund weichzeichnen

„blur behind“ (Unschärfe dahinter) macht den gesamten Bildschirm hinter dem Fenster unscharf. Dieser Effekt wird verwendet, um die Aufmerksamkeit des Nutzers auf den Fensterinhalt zu lenken, indem alles auf dem Bildschirm hinter dem Fenster unscharf dargestellt wird.

So machen Sie den Inhalt hinter dem Fenster unscharf:

  1. Fügen Sie den Fenster-Flags FLAG_BLUR_BEHIND hinzu, um die Unschärfe im Hintergrund zu aktivieren. Oder legen Sie im Fensterdesign R.attr.windowBlurBehindEnabled fest.

  2. Rufen Sie WindowManager.LayoutParams#setBlurBehindRadius auf, um einen Radius für die Unschärfe hinter dem Fenster festzulegen. Oder legen Sie im Fensterdesign R.attr.windowBlurBehindRadius fest.

  3. Optional können Sie einen ergänzenden Dimmbetrag auswählen.

  4. Aktivierte und deaktivierte Zustände für die Unschärfe verarbeiten. Weitere Informationen findest du im Abschnitt Richtlinien für die Verwendung von Fensterunschärfe in Apps.

Richtlinien für die Verwendung von Fensterunschärfe in Apps

Die Unterstützung für das Weichzeichnen von Fenstern hängt von Folgendem ab:

  • Android-Version: Die APIs für die Fensterunschärfe sind nur unter Android 12 und höher verfügbar. Prüfen Sie das SDK des Geräts auf die Android-Version.

  • Grafikleistung: Auf Geräten mit weniger leistungsstarken GPUs wird die Fensterunschärfemöglicherweise nicht unterstützt.

  • Systemstatus: Der Systemserver kann Fensterunschärfen zur Laufzeit vorübergehend deaktivieren, z. B. im Energiesparmodus, bei der Wiedergabe bestimmter Arten von Videoinhalten oder aufgrund einer Entwicklerüberschreibung.

Damit deine App mit allen Android-Versionen, Geräten und Systemstatus kompatibel ist, solltest du die folgenden Richtlinien beachten:

  • Füge über WindowManager#addCrossWindowBlurEnabledListener einen Listener hinzu, um benachrichtigt zu werden, wenn die Fensterunschärfe aktiviert oder deaktiviert wird. Außerdem können Sie mit WindowManager#isCrossWindowBlurEnabled abfragen, ob Fensterunschärfen derzeit aktiviert sind.

  • Implementiere zwei Versionen für den Fensterhintergrund, um den aktivierten oder deaktivierten Status der Fensterunschärfe zu berücksichtigen.

    Wenn Unschärfen aktiviert sind, sollte der Fensterhintergrund durchscheinend sein, damit die Unschärfe sichtbar ist. Wenn in diesem Zustand die Unschärfe deaktiviert wird, überlappt der Fensterinhalt direkt mit dem Inhalt des darunter liegenden Fensters, sodass das überlappende Fenster weniger gut lesbar ist. Wenn Fensterunschärfen deaktiviert sind, können Sie die Benutzeroberfläche der App so anpassen, dass dieser Effekt vermieden wird:

    • Erhöhe für die Hintergrundunschärfe den Alphawert des Fensterhintergrund-Drawables, um es undurchsichtiger zu machen.

    • Wenn du den Hintergrund weichzeichnen möchtest, füge eine Abdunklungsebene mit einem höheren Abdunklungswert hinzu.

Beispiel für „Hintergrund weichzeichnen“ und „Hintergrund weichzeichnen“

In diesem Abschnitt finden Sie ein funktionierendes Beispiel für eine Aktivität, bei der sowohl die Unschärfe hinter dem Fenster als auch die Hintergrundunschärfe verwendet wird.

Das folgende Beispiel für MainActivity.java ist ein Dialogfeld mit einem Radius für die Unschärfe hinter dem Dialogfeld von 20 px und einem Radius für die Hintergrundunschärfe von 80 px. Es hat abgerundete Ecken, die in der XML-Datei im Drawable für den Fensterhintergrund definiert sind. Es verarbeitet verschiedene Android-Versionen, verschiedene Geräte (die möglicherweise keine Fensterunschärfe unterstützen) und Änderungen, die die Laufzeitunschärfe aktivieren oder deaktivieren. Dabei wird sichergestellt, dass der Dialoginhalt unter allen Bedingungen lesbar ist, indem der Alpha-Wert des Fensterhintergrunds und die Abdunklung des Fensters angepasst werden.

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;
    }
}

Um abgerundete Ecken für das Fenster zu erstellen, definieren wir den Fensterhintergrund in res/drawable/window_background.xml als ShapeDrawable mit abgerundeten Ecken mit einem Radius von 20 dp:

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

Bei der Fensterunschärfe wird der Inhalt des Fensters unter der Aktivität unscharf dargestellt. Das weichgezeichnete Bild wird unter diesem Aktivitätsfenster gezeichnet. Das Aktivitätsfenster muss also durchscheinend sein, damit die Weichzeichnung sichtbar ist. Wenn du das Fenster durchscheinend machen möchtest, lege R.attr.windowIsTranslucent im Aktivitätsdesign so fest:

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

OEMs und Partner

Damit ein Gerät Fenster weichzeichnen kann, muss der OEM angeben, dass das Gerät das Weichzeichnen von Fenstern unterstützt.

So prüfen Sie, ob Ihr Gerät Fensterunschärfe unterstützt:

  • Achten Sie darauf, dass das Gerät die zusätzliche GPU-Last bewältigen kann. Geräte mit geringerer Leistung können die zusätzliche Last möglicherweise nicht bewältigen, was zu Frame-Drops führen kann. Aktiviere Fensterunschärfen nur auf getesteten Geräten mit ausreichender GPU-Leistung.

  • Wenn Sie eine benutzerdefinierte Rendering-Engine haben, muss diese die Unkenntlichmachungslogik implementieren. Die standardmäßige Rendering-Engine von Android 12 implementiert die Unschärfelogik in BlurFilter.cpp.

Wenn du sichergestellt hast, dass dein Gerät Fensterunschärfe unterstützt, lege den folgenden SurfaceFlinger-sysprop fest:

PRODUCT_VENDOR_PROPERTIES += \
       ro.surface_flinger.supports_background_blur=1

Validierung

So prüfen Sie, ob Ihr App-Fenster beim Wechsel zwischen aktiviertem und deaktiviertem Unschärfeeffekt richtig verarbeitet wird:

  1. Öffnen Sie die Benutzeroberfläche, die unscharf ist.

  2. Sie können die Fensterunschärfe aktivieren oder deaktivieren, indem Sie die Fensterunschärfe ein- und ausschalten.

  3. Prüfen Sie, ob die Fenster-UI wie erwartet in einen unscharfen Zustand wechselt und wieder zurück.

Fensterunschärfe aktivieren und deaktivieren

Wenn Sie testen möchten, wie die Fenster-UI mit dem Fensterunschärfeeffekt gerendert wird, aktivieren oder deaktivieren Sie die Unschärfe mit einer der folgenden Methoden:

  • Über die Entwickleroptionen:

    Einstellungen -> System -> Entwickleroptionen -> Hardwarebeschleunigtes Rendering -> Unschärfe auf Fensterebene zulassen

  • Über das Terminal auf einem gerooteten Gerät:

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

Wenn du prüfen möchtest, ob dein Gerät mit Android 12 oder höher Fensterunschärfen unterstützt und ob Fensterunschärfen derzeit aktiviert sind, führe adb shell wm disable-blur auf einem gerooteten Gerät aus.

Fehlerbehebung

Verwenden Sie die folgenden Informationen als Leitfaden für die Fehlerbehebung während der Validierung.

Keine Unkenntlichmachung gezeichnet

  • Prüfen Sie, ob die Weichzeichnung derzeit aktiviert ist und von Ihrer Hardware unterstützt wird. Weitere Informationen finden Sie unter Fensterunschärfe aktivieren und deaktivieren.

  • Achten Sie darauf, eine durchscheinende Fensterhintergrundfarbe festzulegen. Eine undurchsichtige Fensterhintergrundfarbe verbirgt den unscharfen Bereich.

Testgerät unterstützt keine Fensterunschärfe

  • Testen Sie Ihre Anwendung im Android 12-Emulator. Informationen zum Einrichten eines Android-Emulators finden Sie unter Android-Emulator einrichten. Alle virtuellen Android-Geräte, die Sie mit dem Emulator erstellen, unterstützen die Fensterunschärfe.

Keine abgerundeten Ecken

Durch das Aktualisieren der Entwickleroption werden Unschärfen nicht aktiviert.

  • Prüfe, ob sich das Gerät im Energiesparmodus befindet oder ob es Multimedia-Tunneling verwendet. Auf einigen TV-Geräten ist die Fensterunschärfe möglicherweise auch während der Videowiedergabe deaktiviert.

Weichgezeichneter Hintergrund wird im Vollbildmodus und nicht innerhalb der Fenstergrenzen angezeigt

Updates vom Listener werden nicht auf dem Bildschirm angewendet

  • Die Listener-Updates werden möglicherweise auf eine alte Fensterinstanz angewendet. Prüfen Sie, ob das Fenster zerstört und mit dem richtigen Listener-Update neu erstellt wird.