Obsługa wycięć w ekranie

Wypróbuj Compose
Jetpack Compose to zalecany zestaw narzędzi do tworzenia interfejsu na Androidzie. Dowiedz się, jak pracować z wycięciami w ekranie w Compose.

Wycięcie w ekranie to obszar na niektórych urządzeniach który wchodzi w powierzchnię wyświetlacza. Umożliwia to wyświetlanie treści bez ramki, a jednocześnie zapewnia miejsce na ważne czujniki z przodu urządzenia.

Android obsługuje wycięcia w ekranie na urządzeniach z Androidem 9 (poziom 28 interfejsu API) i nowszym. Producenci urządzeń mogą jednak obsługiwać wycięcia w ekranie również na urządzeniach z Androidem 8.1 lub starszym.

Z tego dokumentu dowiesz się, jak zaimplementować obsługę urządzeń z wycięciami, w tym jak pracować z obszarem wycięcia—czyli prostokątem bez ramki na powierzchni wyświetlacza, który zawiera wycięcie.

Obraz przedstawiający przykład wycięcia w ekranie u góry na środku
Rysunek 1. 1 Wycięcie w ekranie.

Wybieranie sposobu obsługi obszarów wycięcia przez aplikację

Jeśli nie chcesz, aby treści nakładały się na obszar wycięcia, wystarczy zwykle upewnić się, że nie nakładają się one na pasek stanu i pasek nawigacyjny. Jeśli renderujesz w obszarze wycięcia, użyj WindowInsetsCompat.getDisplayCutout() aby pobrać obiekt DisplayCutout który zawiera bezpieczne wcięcia i ramkę ograniczającą dla każdego wycięcia. Te interfejsy API umożliwiają sprawdzenie, czy treści nakładają się na wycięcie, dzięki czemu możesz w razie potrzeby zmienić ich położenie.

Możesz też określić, czy treści są rozmieszczone za obszarem wycięcia. Atrybut układu okna layoutInDisplayCutoutMode określa, jak treści są rysowane w obszarze wycięcia. Możesz ustawić layoutInDisplayCutoutMode na jedną z tych wartości:

  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT: treści są renderowane w obszarze wycięcia, gdy wycięcie w ekranie znajduje się na pasku systemu. W przeciwnym razie okno nie nakłada się na wycięcie w ekranie. Na przykład treści mogą być wyświetlane w trybie letterbox, gdy są wyświetlane w trybie poziomym. Jeśli Twoja aplikacja jest kierowana na SDK 35, w przypadku okien niepływających jest to interpretowane jako ALWAYS.
  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS: treści zawsze mogą rozciągać się na obszary wycięcia. Jeśli Twoja aplikacja jest kierowana na SDK 35 i działa na urządzeniu z Androidem 15, jest to jedyny dozwolony tryb dla okien niepływających, który zapewnia wyświetlanie treści bez ramki.
  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES: treści są renderowane w obszarze wycięcia zarówno w trybie pionowym, jak i poziomym. Nie używaj w przypadku okien pływających. Jeśli Twoja aplikacja jest kierowana na SDK 35, w przypadku okien niepływających jest to interpretowane jako ALWAYS.
  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER: treści nigdy nie są renderowane w obszarze wycięcia. Jeśli Twoja aplikacja jest kierowana na SDK 35, w przypadku okien niepływających jest to interpretowane jako ALWAYS.

Tryb wycięcia możesz ustawić programowo lub przez ustawienie a stylu w aktywności. W tym przykładzie zdefiniowano styl, który stosuje atrybut LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES do aktywności.

<style name="ActivityTheme">
  <item name="android:windowLayoutInDisplayCutoutMode">
    shortEdges <!-- default, shortEdges, or never -->
  </item>
</style>

W kolejnych sekcjach opisujemy szczegółowo różne tryby wycięcia.

Działanie domyślne

Jeśli Twoja aplikacja jest kierowana na SDK 35 i działa na urządzeniu z Androidem 15, LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS jest domyślnym działaniem, a LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT jest interpretowane jako LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS w przypadku okien niepływających.

W przeciwnym razie domyślnym ustawieniem jest LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT.

Renderowanie treści w obszarach wycięcia na krótkich krawędziach

Jeśli Twoja aplikacja jest kierowana na SDK 35 i działa na urządzeniu z Androidem 15, LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES jest interpretowane jako LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS w przypadku okien niepływających.

W przypadku LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES treści rozciągają się na obszar wycięcia na krótkiej krawędzi wyświetlacza zarówno w trybie pionowym, jak i poziomym, niezależnie od tego, czy paski systemu są ukryte czy widoczne. Gdy używasz tego trybu, upewnij się, że żadne ważne treści nie nakładają się na obszar wycięcia.

Ten obraz przedstawia przykład LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES na urządzeniu w trybie pionowym:

Ilustracja pokazująca renderowanie treści w obszarze wycięcia w trybie pionowym
Rysunek 2. Renderowanie treści w obszarze wycięcia w trybie pionowym.

Ten obraz przedstawia przykład LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES na urządzeniu w trybie poziomym:

Obraz przedstawiający treści renderowane w obszarze wycięcia w trybie poziomym
Rysunek 3. Renderowanie treści w obszarze wycięcia w trybie poziomym.

W tym trybie okno rozciąga się pod wycięcia na krótkiej krawędzi wyświetlacza zarówno w trybie pionowym, jak i poziomym, niezależnie od tego, czy okno ukrywa paski systemu.

Wycięcie w rogu jest uważane za wycięcie na krótkiej krawędzi:

Ilustracja przedstawiająca urządzenie z wycięciem w rogu
Rysunek 4. Urządzenie z wycięciem w rogu.

Nigdy nie renderuj treści w obszarze wycięcia w ekranie

Jeśli Twoja aplikacja jest kierowana na SDK 35 i działa na urządzeniu z Androidem 15, LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER jest interpretowane jako LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS w przypadku okien niepływających.

W przypadku LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER okno nigdy nie może nakładać się na obszar wycięcia.

Oto przykład LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER w trybie pionowym:

Ilustracja pokazująca wartość LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER w przypadku orientacji pionowej
Rysunek 5. Przykład LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER w trybie pionowym.

Oto przykład LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER w trybie poziomym:

Ilustracja pokazująca LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER w przypadku orientacji poziomej
Rysunek 6. Przykład LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER w trybie poziomym.

Sprawdzone metody obsługi wycięć w ekranie

Podczas pracy z wycięciami w ekranie pamiętaj o tych kwestiach:

  • Zwróć uwagę na umiejscowienie najważniejszych elementów interfejsu. Nie dopuść do tego, aby obszar wycięcia zasłaniał ważne teksty, elementy sterujące lub inne informacje.
  • Nie umieszczaj ani nie rozciągaj w obszarze wycięcia żadnych elementów interaktywnych, które wymagają precyzyjnego dotyku. Czułość ekranu w obszarze wycięcia może być mniejsza.
  • Jeśli to możliwe, użyj WindowInsetsCompat, aby pobrać wysokość paska stanu i określić odpowiedni odstęp, który należy zastosować do treści. Unikaj kodowania na stałe wysokości paska stanu, ponieważ może to powodować nakładanie się lub ucinanie treści.

    Obraz przedstawiający treść uciętą u góry z powodu nieprawidłowej konfiguracji wcięć
    Rysunek 7. Użyj WindowInsetsCompat, aby uniknąć nakładania się lub ucinania treści.
  • Użyj View.getLocationInWindow() , aby określić, ile miejsca w oknie zajmuje Twoja aplikacja. Nie zakładaj, że aplikacja zajmuje całe okno, i nie używaj View.getLocationOnScreen().

  • Jeśli Twoja aplikacja musi przechodzić do trybu immersyjnego i z niego wychodzić, użyj trybów wycięcia always, shortEdges lub never. Domyślne działanie wycięcia może powodować, że treści w aplikacji będą renderowane w obszarze wycięcia, gdy paski systemu są widoczne, ale nie w trybie immersyjnym. Powoduje to przesuwanie się treści w górę i w dół podczas przejść, jak pokazano w tym przykładzie.

    Ilustracja przedstawiająca treści przesuwające się w górę i w dół podczas przejść.
    Rysunek 8. Przykład przesuwania się treści w górę i w dół podczas przejść.
  • W trybie immersyjnym uważaj na używanie współrzędnych okna i ekranu, ponieważ w trybie letterbox aplikacja nie zajmuje całego ekranu. Ze względu na tryb letterbox współrzędne od początku ekranu nie są takie same jak współrzędne od początku okna. W razie potrzeby możesz przekształcić współrzędne ekranu na współrzędne widoku za pomocą getLocationOnScreen(). Ten obraz pokazuje, jak różnią się współrzędne, gdy treści są wyświetlane w trybie letterbox:

    Obraz przedstawiający współrzędne okna i ekranu, gdy treść jest wyświetlana w formacie letterbox.
    Rysunek 9. Współrzędne okna i ekranu, gdy treści są wyświetlane w trybie letterbox.
  • Podczas obsługi MotionEvent używaj MotionEvent.getX() i MotionEvent.getY(), aby uniknąć podobnych problemów ze współrzędnymi. Nie używaj MotionEvent.getRawX() ani MotionEvent.getRawY().

Testowanie renderowania treści

Przetestuj wszystkie ekrany i funkcje aplikacji. Jeśli to możliwe, przetestuj aplikację na urządzeniach z różnymi typami wycięć. Jeśli nie masz urządzenia z wycięciem, możesz symulować typowe konfiguracje wycięć na dowolnym urządzeniu lub emulatorze z Androidem 9 lub nowszym, wykonując te czynności:

  1. Włącz Opcje programisty.
  2. Na ekranie Opcje programisty przewiń w dół do sekcji Rysowanie i wybierz Symuluj wyświetlacz z wycięciem.
  3. Wybierz typ wycięcia.

    Ilustracja pokazująca, jak symulować wycięcie w ekranie w emulatorze
    Rysunek 10. Opcje programisty do testowania renderowania treści.

Dodatkowe materiały