Gdy kierujesz aplikację na pakiet SDK 35 lub nowszy na urządzeniu z Androidem 15 lub nowszym, aplikacja wyświetla się bez ramki. Okno zajmuje całą szerokość i wysokość wyświetlacza, ponieważ jest rysowane za paskami systemowymi. Paski systemowe to pasek stanu, pasek tytułu i pasek nawigacji.
Wiele aplikacji ma górny pasek aplikacji. Górny pasek aplikacji powinien rozciągać się do górnej krawędzi ekranu i wyświetlać się za paskiem stanu. Opcjonalnie górny pasek aplikacji może się zmniejszyć do wysokości paska stanu podczas przewijania treści.
Wiele aplikacji ma też dolny pasek aplikacji lub dolny pasek nawigacyjny. Paski te powinny też rozciągać się do dolnej krawędzi ekranu i wyświetlać się za paskiem nawigacyjnym. W przeciwnym razie aplikacje powinny wyświetlać przewijane treści za paskiem nawigacyjnym.
Podczas wdrażania w aplikacji układu od krawędzi do krawędzi pamiętaj o tych kwestiach:
- Włącz wyświetlanie bez ramki
- Rozwiąż problemy z nakładaniem się elementów wizualnych.
- Rozważ umieszczenie za belkami systemu ekranów.

Włącz wyświetlanie bez ramki
Jeśli Twoja aplikacja jest kierowana na SDK 35 lub nowszy, wyświetlanie bez ramki jest automatycznie włączane na urządzeniach z Androidem 15 lub nowszym.
Aby włączyć wyświetlanie od krawędzi do krawędzi w starszych wersjach Androida, ręcznie wywołaj enableEdgeToEdge
w onCreate
swojego Activity
.
Kotlin
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.enableEdgeToEdge(window)
...
}
Java
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WindowCompat.enableEdgeToEdge(getWindow());
...
}
Domyślnie enableEdgeToEdge()
sprawia, że paski systemowe są przezroczyste, z wyjątkiem trybu nawigacji 3-przyciskowej, w którym pasek stanu jest półprzezroczysty. Kolory ikon systemowych i półprzezroczystej nakładki są dostosowywane do jasnego lub ciemnego motywu systemu.
Aby włączyć wyświetlanie bez ramki w aplikacji bez używania funkcji
enableEdgeToEdge()
, przeczytaj artykuł
Ręczne konfigurowanie wyświetlania bez ramki.
Obsługa nakładania się elementów za pomocą wcięć
Niektóre widoki aplikacji mogą być rysowane za paskami systemu, jak pokazano na rysunku 3.
Możesz rozwiązać problem z nakładaniem się elementów, reagując na wcięcia, które określają, które części ekranu przecinają się z interfejsem systemu, takim jak pasek nawigacyjny lub pasek stanu. Nakładanie się może oznaczać wyświetlanie nad treścią, ale może też informować aplikację o gestach systemowych.
Typy wcięć, które mają zastosowanie do wyświetlania aplikacji bez ramki:
Wstawki pasków systemowych: najlepsze w przypadku widoków, w które można kliknąć i które nie mogą być wizualnie zasłonięte przez paski systemowe.
Wcięcia w wycięciu ekranu: w przypadku obszarów, w których może występować wycięcie ekranu ze względu na kształt urządzenia.
Wstawki gestów systemowych: obszary nawigacji gestami używane przez system, które mają wyższy priorytet niż Twoja aplikacja.
Wstawki paska systemowego
Wstawki paska systemowego są najczęściej używanym typem wstawek. Reprezentują one obszar, w którym interfejs systemu wyświetla się na osi Z nad aplikacją. Najlepiej używać ich do przesuwania lub wypełniania widoków w aplikacji, które można kliknąć i które nie mogą być wizualnie zasłonięte przez paski systemowe.
Na przykład pływający przycisk działania (FAB) na rysunku 3 jest częściowo zasłonięty przez pasek nawigacyjny:

Aby uniknąć tego rodzaju nakładania się elementów w trybie gestów lub trybie przycisków, możesz zwiększyć marginesy widoku za pomocą funkcji getInsets(int)
z parametrem WindowInsetsCompat.Type.systemBars()
.
Poniższy przykład kodu pokazuje, jak zaimplementować wstawki paska systemowego:
Kotlin
ViewCompat.setOnApplyWindowInsetsListener(fab) { v, windowInsets -> val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) // Apply the insets as a margin to the view. This solution sets // only the bottom, left, and right dimensions, but you can apply whichever // insets are appropriate to your layout. You can also update the view padding // if that's more appropriate. v.updateLayoutParams<MarginLayoutParams> { leftMargin = insets.left bottomMargin = insets.bottom rightMargin = insets.right } // Return CONSUMED if you don't want the window insets to keep passing // down to descendant views. WindowInsetsCompat.CONSUMED }
Java
ViewCompat.setOnApplyWindowInsetsListener(fab, (v, windowInsets) -> { Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()); // Apply the insets as a margin to the view. This solution sets only the // bottom, left, and right dimensions, but you can apply whichever insets are // appropriate to your layout. You can also update the view padding if that's // more appropriate. MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams(); mlp.leftMargin = insets.left; mlp.bottomMargin = insets.bottom; mlp.rightMargin = insets.right; v.setLayoutParams(mlp); // Return CONSUMED if you don't want the window insets to keep passing // down to descendant views. return WindowInsetsCompat.CONSUMED; });
Jeśli zastosujesz to rozwiązanie w przykładzie pokazanym na rysunku 3, w trybie przycisku nie będzie żadnego nakładania się elementów wizualnych, jak pokazano na rysunku 4:

To samo dotyczy trybu nawigacji przy użyciu gestów, jak pokazano na rysunku 5:

Wstawki wycięcia w ekranie
Niektóre urządzenia mają wycięcia na wyświetlaczu. Zwykle wycięcie znajduje się u góry ekranu i jest częścią paska stanu. Gdy ekran urządzenia jest w trybie poziomym, wycięcie może znajdować się na pionowej krawędzi. W zależności od treści wyświetlanych przez aplikację na ekranie należy zastosować dopełnienie, aby uniknąć wycięć na wyświetlaczu, ponieważ domyślnie aplikacje będą rysować w wycięciu na wyświetlaczu.
Na przykład na wielu ekranach aplikacji wyświetlana jest lista elementów. Nie zasłaniaj elementów listy wycięciem na wyświetlaczu ani paskami systemowymi.
Kotlin
ViewCompat.setOnApplyWindowInsetsListener(binding.recyclerView) { v, insets -> val bars = insets.getInsets( WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout() ) v.updatePadding( left = bars.left, top = bars.top, right = bars.right, bottom = bars.bottom, ) WindowInsetsCompat.CONSUMED }
Java
ViewCompat.setOnApplyWindowInsetsListener(mBinding.recyclerView, (v, insets) -> { Insets bars = insets.getInsets( WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout() ); v.setPadding(bars.left, bars.top, bars.right, bars.bottom); return WindowInsetsCompat.CONSUMED; });
Określ wartość WindowInsetsCompat
, wykonując logiczną operację OR na paskach systemowych i typach wycięcia na wyświetlaczu.
Ustaw wartość clipToPadding
na RecyclerView
, aby dopełnienie przewijało się wraz z elementami listy. Dzięki temu elementy mogą znajdować się za paskami systemowymi, gdy użytkownik przewija stronę, jak pokazano w przykładzie poniżej.
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
Wstawki gestów systemowych
Wstawki gestów systemowych to obszary okna, w których gesty systemowe mają wyższy priorytet niż aplikacja. Obszary te są oznaczone na pomarańczowo na rysunku 6:

Podobnie jak w przypadku wcięć paska systemowego możesz uniknąć nakładania się wcięć gestów systemowych, używając getInsets(int)
z WindowInsetsCompat.Type.systemGestures()
.
Użyj tych wcięć, aby przesunąć widoki, które można przesuwać, lub dodać do nich dopełnienie, tak aby nie znajdowały się przy krawędziach. Typowe przypadki użycia to arkusze u dołu ekranu, przesuwanie w grach i karuzele zaimplementowane za pomocą ViewPager2
.
W Androidzie 10 lub nowszym odcięcia gestów systemowych obejmują odcięcie dolne dla gestu głównego oraz odcięcia po lewej i prawej stronie dla gestów wstecz:

Poniższy przykład kodu pokazuje, jak zaimplementować wstawki gestów systemowych:
Kotlin
ViewCompat.setOnApplyWindowInsetsListener(view) { view, windowInsets -> val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures()) // Apply the insets as padding to the view. Here, set all the dimensions // as appropriate to your layout. You can also update the view's margin if // more appropriate. view.updatePadding(insets.left, insets.top, insets.right, insets.bottom) // Return CONSUMED if you don't want the window insets to keep passing down // to descendant views. WindowInsetsCompat.CONSUMED }
Java
ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> { Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures()); // Apply the insets as padding to the view. Here, set all the dimensions // as appropriate to your layout. You can also update the view's margin if // more appropriate. view.setPadding(insets.left, insets.top, insets.right, insets.bottom); // Return CONSUMED if you don't want the window insets to keep passing down // to descendant views. return WindowInsetsCompat.CONSUMED; });
Komponenty Material
Wiele komponentów Android Material Components (com.google.android.material) opartych na widokach automatycznie obsługuje wcięcia, w tym BottomAppBar
, BottomNavigationView
, NavigationRailView
i NavigationView
.
Jednak AppBarLayout
nie obsługuje automatycznie wcięć. Dodaj
android:fitsSystemWindows="true"
do obsługi górnych wcięć.
Dowiedz się, jak obsługiwać wcięcia za pomocą komponentów Material w Compose.
Wysyłanie wstawek zgodnych wstecznie
Aby zapobiec wysyłaniu wstawek do widoków dzieci i uniknąć nadmiernego dopełnienia, możesz wykorzystać wstawki za pomocą stałej WindowInsetsCompat.CONSUMED
. Jednak na urządzeniach z Androidem 10 (poziom interfejsu API 29 i starsze) po wywołaniu WindowInsetsCompat.CONSUMED
elementy wstawki nie są wysyłane do elementów równorzędnych, co może powodować niezamierzone nakładanie się elementów.

Aby potwierdzić, że elementy wstawki są wysyłane do elementów równorzędnych we wszystkich obsługiwanych wersjach Androida, użyj funkcji ViewGroupCompat#installCompatInsetsDispatch
before consuming
insets, dostępnej w AndroidX Core i Core-ktx w wersji 1.16.0-alpha01 lub nowszej.
Kotlin
// Use the i.d. assigned to your layout's root view, e.g. R.id.main val rootView = findViewById(R.id.main) // Call before consuming insets ViewGroupCompat.installCompatInsetsDispatch(rootView)
Java
// Use the i.d. assigned to your layout's root view, e.g. R.id.main LinearLayout rootView = findViewById(R.id.main); // Call before consuming insets ViewGroupCompat.installCompatInsetsDispatch(rootView);

Tryb pojemny
Niektóre treści najlepiej wyświetlać na pełnym ekranie, co zapewnia użytkownikom większe zaangażowanie. Paski systemowe możesz ukryć w trybie pełnoekranowym za pomocą bibliotek WindowInsetsController
i WindowInsetsControllerCompat
:
Kotlin
val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView) // Hide the system bars. windowInsetsController.hide(Type.systemBars()) // Show the system bars. windowInsetsController.show(Type.systemBars())
Java
Window window = getWindow(); WindowInsetsControllerCompat windowInsetsController = WindowCompat.getInsetsController(window, window.getDecorView()); if (windowInsetsController == null) { return; } // Hide the system bars. windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()); // Show the system bars. windowInsetsController.show(WindowInsetsCompat.Type.systemBars());
Więcej informacji o wdrażaniu tej funkcji znajdziesz w artykule Ukrywanie pasków systemowych w trybie pełnoekranowym.
Ikony na pasku systemowym
Wywołanie enableEdgeToEdge
zapewnia aktualizację kolorów ikon na pasku systemowym po zmianie motywu urządzenia.
Podczas przechodzenia od krawędzi do krawędzi może być konieczne ręczne zaktualizowanie kolorów ikon paska systemowego, aby kontrastowały z tłem aplikacji. Aby na przykład utworzyć jasne ikony paska stanu:
Kotlin
WindowCompat.getInsetsController(window, window.decorView) .isAppearanceLightStatusBars = false
Java
WindowCompat.getInsetsController(window, window.getDecorView()) .setAppearanceLightStatusBars(false);
Ochrona paska systemowego
Gdy aplikacja będzie kierowana na pakiet SDK w wersji 35 lub nowszej, wyświetlanie od krawędzi do krawędzi będzie wymuszane.
Pasek stanu systemu i paski nawigacji przy użyciu gestów są przezroczyste, ale pasek nawigacji przy użyciu 3 przycisków jest półprzezroczysty. Zadzwoń pod numer enableEdgeToEdge
, aby ustawić zgodność wsteczną.
Jednak domyślne ustawienia systemu mogą nie działać w przypadku wszystkich zastosowań. Zapoznaj się z wskazówkami dotyczącymi projektowania pasków systemowych na Androidzie i projektowaniem od krawędzi do krawędzi, aby określić, czy używać przezroczystych czy półprzezroczystych pasków systemowych.
Tworzenie przezroczystych pasków systemowych
Utwórz przezroczysty pasek stanu, kierując reklamy na Androida 15 (SDK 35) lub nowszego albo wywołując funkcję enableEdgeToEdge()
z argumentami domyślnymi w przypadku starszych wersji.
Utwórz przezroczysty pasek nawigacyjny gestów, kierując reklamy na Androida 15 lub nowszego albo wywołując enableEdgeToEdge()
z argumentami domyślnymi w przypadku starszych wersji. W przypadku 3-przyciskowego paska nawigacyjnego ustaw wartość Window.setNavigationBarContrastEnforced
na false
. W przeciwnym razie zostanie zastosowana półprzezroczysta zasłona.
Tworzenie półprzezroczystych pasków systemowych
Aby utworzyć półprzezroczysty pasek stanu:
- Zaktualizuj zależność
androidx-core
do wersji 1.16.0-beta01 lub nowszej. - Owiń układ XML w tagi
androidx.core.view.insets.ProtectionLayout
i przypisz identyfikator. - Programowo uzyskaj dostęp do
ProtectionLayout
, aby ustawić ochronę, określając stronę iGradientProtection
dla paska stanu.
<androidx.core.view.insets.ProtectionLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/list_protection" android:layout_width="match_parent" android:layout_height="match_parent"> <ScrollView android:id="@+id/item_list" android:clipToPadding="false" android:layout_width="match_parent" android:layout_height="match_parent"> <!--items--> </ScrollView> </androidx.core.view.insets.ProtectionLayout>
findViewById<ProtectionLayout>(R.id.list_protection) .setProtections( listOf( GradientProtection( WindowInsetsCompat.Side.TOP, // Ideally, this is the pane's background color paneBackgroundColor ) ) )
Sprawdź, czy wartość parametru ColorInt
przekazywana do parametru GradientProtection
jest zgodna z tłem treści. Na przykład układ lista-szczegóły wyświetlany na urządzeniu składanym może mieć różne GradientProtections
w różnych kolorach dla panelu listy i panelu szczegółów.
Nie twórz półprzezroczystego paska nawigacyjnego opartego na gestach. Aby utworzyć półprzezroczysty pasek nawigacyjny z 3 przyciskami, wykonaj jedną z tych czynności:
- Jeśli układ jest już zawarty w elemencie
ProtectionView
, możesz przekazać dodatkowy elementColorProtection
lubGradientProtection
do metodysetProtections
. Zanim to zrobisz, upewnij się, żewindow.isNavigationBarContrastEnforced = false
. - W przeciwnym razie ustaw
window.isNavigationBarContrastEnforced = true
. Jeśli połączeniaenableEdgeToEdge, window.isNavigationBarContrastEnforced = true
w aplikacji są domyślne.
Inne wskazówki
Dodatkowe wskazówki dotyczące obsługi wstawek.
Wyświetlanie treści przewijanych od krawędzi do krawędzi
Sprawdź, czy ostatni element listy nie jest zasłonięty przez paski systemowe w RecyclerView
lub NestedScrollView
, obsługując wstawki i ustawiając clipToPadding
na false
.
Poniższy film pokazuje RecyclerView
z wyłączonym (po lewej) i włączonym (po prawej) wyświetlaczem od krawędzi do krawędzi:
Przykłady kodu znajdziesz w sekcji Tworzenie dynamicznych list za pomocą elementu RecyclerView.
Wyświetlanie okien pełnoekranowych od krawędzi do krawędzi
Aby okno pełnoekranowe zajmowało cały ekran, wywołaj enableEdgeToEdge
w oknie.
Kotlin
class MyAlertDialogFragment : DialogFragment() {
override fun onStart(){
super.onStart()
dialog?.window?.let { WindowCompat.enableEdgeToEdge(it) }
}
...
}
Java
public class MyAlertDialogFragment extends DialogFragment {
@Override
public void onStart() {
super.onStart();
Dialog dialog = getDialog();
if (dialog != null) {
Window window = dialog.getWindow();
if (window != null) {
WindowCompat.enableEdgeToEdge(window);
}
}
}
...
}
Dodatkowe materiały
Więcej informacji o wyświetlaniu treści od krawędzi do krawędzi znajdziesz w tych materiałach:
Blogi
- Wskazówki dotyczące obsługi wcięć w Androidzie 15 w przypadku wymuszania wyświetlania od krawędzi do krawędzi
- WindowInsets – detektory układów
Design
Inna dokumentacja
Filmy