W Androidzie 12 dostępne są publiczne interfejsy API do implementowania efektów rozmycia okna, takich jak rozmycie tła i rozmycie za oknem.
Rozmycie okna lub rozmycie między oknami służy do rozmycia ekranu za danym oknem. Dostępne są 2 rodzaje rozmycia okna, które pozwalają uzyskać różne efekty wizualne:
Rozmycie tła umożliwia tworzenie okien z rozmytym tłem, co daje efekt matowego szkła.
Rozmycie tła pozwala rozmyć cały ekran za oknem (dialogowym), tworząc efekt głębi ostrości.
Obu efektów można używać osobno lub razem, jak pokazano na tym rysunku:
a |
b |
![]() c |
Rysunek 1. Tylko rozmycie tła (a), tylko rozmycie za obiektem (b), rozmycie tła i rozmycie za obiektem (c)
Funkcja rozmycia okna działa we wszystkich oknach, co oznacza, że działa również wtedy, gdy za oknem znajduje się inna aplikacja. Ten efekt różni się od efektu renderowania rozmycia, który rozmywa zawartość wewnątrz tego samego okna. Rozmycie okna jest przydatne w przypadku okien, plansz dolnych i innych pływających okien.
Implementacja
Programiści aplikacji
Aby utworzyć efekt rozmycia, deweloperzy aplikacji muszą podać promień rozmycia. Promień rozmycia określa gęstość rozmycia, czyli im większy promień, tym gęstsze rozmycie. Wartość 0 px oznacza brak rozmycia. W przypadku rozmycia tła promień 20 pikseli daje dobry efekt głębi ostrości, a promień 80 pikseli – dobry efekt matowego szkła. Unikaj promieni rozmycia większych niż 150 pikseli, ponieważ będzie to miało znaczny wpływ na wydajność.
Aby uzyskać pożądany efekt rozmycia i zwiększyć czytelność, wybierz wartość promienia rozmycia uzupełnioną półprzezroczystą warstwą koloru.
Rozmycie tła
Używaj rozmycia tła w pływających oknach, aby utworzyć efekt tła okna, który jest rozmytym obrazem treści pod spodem. Aby dodać rozmyte tło do okna, wykonaj te czynności:
Wywołaj Window#setBackgroundBlurRadius(int), aby ustawić promień rozmycia tła. Możesz też ustawić R.attr.windowBackgroundBlurRadius w motywie okna.
Ustaw R.attr.windowIsTranslucent na wartość „true”, aby okno było półprzezroczyste. Rozmycie jest rysowane pod powierzchnią okna, więc okno musi być półprzezroczyste, aby rozmycie było widoczne.
Opcjonalnie wywołaj Window#setBackgroundDrawableResource(int), aby dodać prostokątne tło okna z półprzezroczystym kolorem. Możesz też ustawić R.attr.windowBackground w motywie okna.
W przypadku okna z zaokrąglonymi rogami określ zaokrąglone rogi rozmytego obszaru, ustawiając ShapeDrawable z zaokrąglonymi rogami jako element rysowalny tła okna.
Obsługuj stany włączenia i wyłączenia rozmycia. Więcej informacji znajdziesz w sekcji Wskazówki dotyczące używania rozmycia okna w aplikacjach.
Rozmycie tła
Rozmycie tła rozmywa cały ekran za oknem. Ten efekt służy do kierowania uwagi użytkownika na zawartość okna przez rozmycie wszystkiego na ekranie za oknem.
Aby rozmyć zawartość za oknem, wykonaj te czynności:
Aby włączyć rozmycie tła, dodaj
FLAG_BLUR_BEHINDdo flag okna. Możesz też ustawić R.attr.windowBlurBehindEnabled w motywie okna.Wywołaj funkcję
WindowManager.LayoutParams#setBlurBehindRadius, aby ustawić promień rozmycia tła. Możesz też ustawić R.attr.windowBlurBehindRadius w motywie okna.Opcjonalnie możesz wybrać uzupełniającą wartość przyciemnienia.
Obsługuj stany włączenia i wyłączenia rozmycia. Więcej informacji znajdziesz w sekcji Wskazówki dotyczące używania rozmycia okna w aplikacjach.
Wskazówki dotyczące korzystania z rozmycia okna w aplikacjach
Obsługa rozmycia okien zależy od tych czynników:
Wersja Androida: interfejsy API rozmycia okien są dostępne tylko na Androidzie 12 i nowszych. Sprawdź pakiet SDK urządzenia pod kątem wersji Androida.
Wydajność grafiki: urządzenia z mniej wydajnymi GPU mogą nie obsługiwać rozmycia okien.
Stan systemu: serwer systemowy może tymczasowo wyłączyć rozmycie okna w czasie działania, na przykład w trybie oszczędzania baterii, podczas odtwarzania niektórych rodzajów treści wideo lub z powodu zastąpienia przez dewelopera.
Aby zapewnić zgodność aplikacji z różnymi wersjami Androida, urządzeniami i stanami systemu, postępuj zgodnie z tymi wytycznymi:
Dodaj detektor za pomocą WindowManager#addCrossWindowBlurEnabledListener, aby otrzymywać powiadomienia o włączeniu lub wyłączeniu rozmycia okna. Dodatkowo użyj
WindowManager#isCrossWindowBlurEnabled, aby sprawdzić, czy rozmycie okna jest obecnie włączone.Zaimplementuj 2 wersje tła okna, aby uwzględnić włączone lub wyłączone rozmycie okna.
Gdy rozmycie jest włączone, tło okna powinno być półprzezroczyste, aby rozmycie było widoczne. W tym stanie, gdy rozmycie jest wyłączone, zawartość okna bezpośrednio nakłada się na zawartość okna pod nim, co sprawia, że nakładające się okno jest mniej czytelne. Aby uniknąć takiego efektu, gdy rozmycie okna jest wyłączone, dostosuj interfejs aplikacji w ten sposób:
Aby rozmyć tło, zwiększ wartość alfa elementu rysowalnego tła okna, aby było bardziej nieprzezroczyste.
Aby rozmyć tło, dodaj warstwę przyciemnienia z większą wartością przyciemnienia.
Przykład rozmycia za obiektem i rozmycia tła
Ta sekcja zawiera działający przykład aktywności, która wykorzystuje zarówno rozmycie tła, jak i rozmycie za elementem.
Poniższy przykład MainActivity.java to okno z rozmyciem za promieniem 20 px i rozmyciem tła o promieniu 80 px. Ma zaokrąglone rogi, które są zdefiniowane w pliku XML w elemencie drawable tła okna. Prawidłowo obsługuje różne wersje Androida, różne urządzenia (które mogą nie obsługiwać rozmycia okna) i zmiany włączania lub wyłączania rozmycia w czasie działania. Zapewnia, że treść okna jest czytelna w każdych warunkach, dostosowując przezroczystość tła okna i stopień przyciemnienia okna.
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;
}
}
Aby utworzyć zaokrąglone rogi okna, definiujemy tło okna w pliku res/drawable/window_background.xml jako ShapeDrawable z zaokrąglonymi rogami o promieniu 20 dp w ten sposób:
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<corners android:radius="20dp"/>
<solid android:color="#AAAAAA"/>
</shape>
Rozmycie okna powoduje rozmycie zawartości okna pod aktywnością. Rozmyty obraz jest rysowany pod oknem aktywności, więc okno aktywności musi być półprzezroczyste, aby rozmycie było widoczne. Aby okno było półprzezroczyste, ustaw R.attr.windowIsTranslucent w motywie aktywności w ten sposób:
<style name="Theme.BlurryDialog" parent="Theme.MaterialComponents.Dialog">
<item name="android:windowIsTranslucent">true</item>
</style>
Producenci OEM i partnerzy
Aby na urządzeniu można było rozmywać okna, producent OEM musi zadeklarować, że urządzenie obsługuje tę funkcję.
Aby sprawdzić, czy urządzenie obsługuje rozmycie okien:
Upewnij się, że urządzenie może obsłużyć dodatkowe obciążenie GPU. Urządzenia niższej klasy mogą nie poradzić sobie z dodatkowym obciążeniem, co może powodować gubienie klatek. Włączaj rozmycie okien tylko na przetestowanych urządzeniach z wystarczającą mocą GPU.
Jeśli masz dostosowany silnik renderowania, upewnij się, że implementuje on logikę rozmycia. Domyślny silnik renderowania Androida 12 implementuje logikę rozmycia w
BlurFilter.cpp.
Gdy upewnisz się, że urządzenie obsługuje rozmycie okien, ustaw te właściwości SurfaceFlingera sysprop:
PRODUCT_VENDOR_PROPERTIES += \
ro.surface_flinger.supports_background_blur=1
Walidacja
Aby sprawdzić, czy okno aplikacji jest prawidłowo obsługiwane podczas przełączania się między stanami z włączonym i wyłączonym rozmyciem, wykonaj te czynności:
Otwórz interfejs z rozmyciem.
Włącz lub wyłącz rozmycie okna, odpowiednio ustawiając przełącznik.
Sprawdź, czy interfejs okna zmienia się zgodnie z oczekiwaniami na stan rozmyty i z powrotem.
Włączanie i wyłączanie rozmycia okna
Aby sprawdzić, jak interfejs okna renderuje się z efektem rozmycia okna, włącz lub wyłącz rozmycie, korzystając z jednej z tych metod:
W opcjach programisty:
Ustawienia -> System -> Opcje programisty -> Akceleracja sprzętowa -> Zezwalaj na rozmycie na poziomie okna
W terminalu na urządzeniu z dostępem do roota:
adb shell wm disable-blur 1 # 1 disables window blurs, 0 allows them
Aby sprawdzić, czy urządzenie z Androidem 12 lub nowszym obsługuje rozmycie okna i czy jest ono obecnie włączone, uruchom adb shell wm disable-blur na urządzeniu z dostępem do roota.
Rozwiązywanie problemów
Poniżej znajdziesz wskazówki dotyczące rozwiązywania problemów podczas weryfikacji.
Nie narysowano rozmycia
Sprawdź, czy rozmycie jest obecnie włączone i czy Twój sprzęt je obsługuje. Więcej informacji znajdziesz w artykule Włączanie i wyłączanie rozmycia okna.
Ustaw półprzezroczysty kolor tła okna. Nieprzezroczysty kolor tła okna ukrywa rozmyty obszar.
Urządzenie testowe nie obsługuje rozmycia okna
- Przetestuj aplikację w emulatorze Androida 12. Aby skonfigurować emulator Androida, zapoznaj się z artykułem Konfigurowanie emulatora Androida. Każde urządzenie wirtualne z Androidem utworzone za pomocą emulatora obsługuje rozmycie okna.
Brak zaokrąglonych rogów
- Ustaw tło okna jako obiekt rysowalny, aby zdefiniować zaokrąglone rogi. Ten element rysowalny określa kontur rozmytego obszaru.
Zaktualizowanie opcji dla programistów nie powoduje włączenia rozmycia.
- Sprawdź, czy urządzenie jest w trybie oszczędzania baterii lub czy korzysta z tunelowania multimediów. Na niektórych telewizorach rozmycie okna może być też wyłączone podczas odtwarzania filmu.
Rozmycie tła jest wyświetlane na pełnym ekranie, a nie w granicach okna
Sprawdź android:windowIsFloating, aby upewnić się, że okno jest oznaczone jako pływające.
Upewnij się, że ustawiono element rysowalny tła okna. To ustawienie określa kontur obszaru rozmycia.
Aktualizacje z odbiornika nie są stosowane na ekranie.
- Aktualizacje detektora mogą być stosowane do starej instancji okna. Sprawdź, czy okno jest niszczone i ponownie tworzone z odpowiednią aktualizacją detektora.
