Wstawienia okien w oknie Utwórz

Platforma Android odpowiada za rysowanie interfejsu systemowego, takiego jak na pasku stanu i nawigacji. Ten interfejs systemu wyświetla się niezależnie aplikacji używanej przez użytkownika.

WindowInsets zawiera informacje o systemie Dopilnuj, aby aplikacja wyświetlała się we właściwym obszarze, a interfejs nie był zasłonięty. przez interfejs systemu.

Od krawędzi do krawędzi w tle słupki systemowe
Rysunek 1. Od krawędzi do krawędzi umieszcza się za słupkami systemowymi.

W Androidzie 14 (poziom interfejsu API 34) i starszych interfejs aplikacji nie jest widoczny pod spodem. z paskami systemowymi i wycięciami w ekranie.

W Androidzie 15 (poziom interfejsu API 35) i nowszym aplikacja jest wyświetlana pod systemem słupki i wycięcia w ekranie, gdy aplikacja jest kierowana na pakiet SDK 35. Dzięki temu zapewnia użytkownikom doskonałe wrażenia i umożliwia aplikacji pełne wykorzystanie dostępną przestrzeń.

Wyświetlanie treści za interfejsem systemowym jest nazywane przetwarzaniem od krawędzi do krawędzi. W: poznasz różne typy wkładek, dowiesz się, jak przejść od krawędzi do krawędzi, i jak używać wbudowanych interfejsów API do animowania UI i dbania o to, by treść aplikacji nie jest zasłonięta przez elementy interfejsu użytkownika systemu.

Podstawy wstawiania

Kiedy aplikacja jest wdrożona na najwyższym poziomie, musisz zadbać o to, by ważne treści które nie są zasłonięte przez interfejs systemu. Jeśli na przykład przycisk to umieszczonego za paskiem nawigacyjnym, użytkownik może nie być w stanie go kliknąć.

Określono rozmiar UI systemu i informacje o jego lokalizacji za pomocą zestawów.

Każda część interfejsu systemu ma odpowiedni typ wstawienia, który opisuje jego rozmiaru i miejsca umieszczenia. Na przykład wcięcia paska stanu podają rozmiar i pozycji paska stanu, a jej wstawki zapewniają rozmiaru i pozycji paska nawigacyjnego. Każdy typ wstawki składa się z 4 elementów. wymiary w pikselach: górna, lewa, prawa i dolna część. Te wymiary określają, jak daleko interfejs systemu wykracza poza odpowiednie boki okna aplikacji. Aby unikać które pokrywają się z tym typem interfejsu systemu, dlatego UI aplikacji musi być umieszczony jako kwotę.

Te wbudowane typy wkładek na Androida są dostępne w WindowInsets:

WindowInsets.statusBars

Wstawki opisujące paski stanu. Są to górne paski interfejsu użytkownika, które zawierają ikony powiadomień i inne wskaźniki.

WindowInsets.statusBarsIgnoringVisibility

Pasek stanu wbudowuje się, gdy jest widoczny. Jeśli paski stanu są obecnie ukryte (z powodu włączenia pełnego ekranu), wstawki głównego paska stanu będą puste, ale nie będą puste.

WindowInsets.navigationBars

Wstawki opisujące paski nawigacyjne. Są to paski interfejsu systemu z lewej, prawej lub u dołu, które opisują pasek aplikacji lub ikony nawigacji. Mogą się one zmieniać w czasie działania w zależności od preferowanej przez użytkownika metody nawigacji oraz interakcji z paskiem aplikacji.

WindowInsets.navigationBarsIgnoringVisibility

Pasek nawigacyjny jest wstawiane, gdy są widoczne. Jeśli paski nawigacyjne są obecnie ukryte (z powodu włączenia pełnego ekranu), wstawki głównego paska nawigacyjnego będą puste, ale nie będą puste.

WindowInsets.captionBar

Wstawka opisująca dekoracje okna interfejsu systemu w przypadku dowolnego okna, np. górny pasek tytułu.

WindowInsets.captionBarIgnoringVisibility

Pasek napisów jest wstawiane, gdy są widoczne. Jeśli paski napisów są obecnie ukryte, główne wcięcia pasków napisów będą puste, ale te wstawki nie będą puste.

WindowInsets.systemBars

Połączenie wcięć pasków systemowych, które obejmują paski stanu, nawigacji i napisów.

WindowInsets.systemBarsIgnoringVisibility

Pasek systemowy jest wstawiane, gdy są widoczne. Jeśli paski systemowe są obecnie ukryte (z powodu włączenia się w tryb pełnego ekranu), główne wcięcia pasków systemowych będą puste, ale nie będą puste.

WindowInsets.ime

Wstawki opisujące ilość miejsca na dole zajmowanego przez klawiaturę programową.

WindowInsets.imeAnimationSource

Wstawki opisujące ilość miejsca zajmowanego przez klawiaturę programową przed bieżącą animacją klawiatury.

WindowInsets.imeAnimationTarget

Wstawki opisujące ilość miejsca, jaką klawiatura programowa zajmie po bieżącej animacji klawiatury.

WindowInsets.tappableElement

Rodzaj wkładek opisujących bardziej szczegółowe informacje o interfejsie nawigacji, które zawierają ilość miejsca, w którym „dotknięcia” jest obsługiwany przez system, a nie aplikację. W przypadku przezroczystych pasków nawigacyjnych z nawigacją przy użyciu gestów niektóre elementy aplikacji można kliknąć w interfejsie nawigacji w systemie.

WindowInsets.tappableElementIgnoringVisibility

Elementy do kliknięcia pojawiają się, gdy są widoczne. Jeśli elementy do kliknięcia są obecnie ukryte (z powodu przejścia w pojemny tryb pełnoekranowy), główne wstawki z elementami do kliknięcia będą puste, ale nie będą puste.

WindowInsets.systemGestures

Wstawki reprezentujące liczbę wektorów, w których system przechwytuje gesty na potrzeby nawigacji. Aplikacje mogą ręcznie określać sposób obsługi ograniczonej liczby tych gestów za pomocą Modifier.systemGestureExclusion.

WindowInsets.mandatorySystemGestures

Zestaw gestów systemowych, które będą zawsze obsługiwane przez system i z których nie można zrezygnować w Modifier.systemGestureExclusion.

WindowInsets.displayCutout

Wcięcia reprezentujące odstępy potrzebne do uniknięcia nakładania się na wycięcie w ekranie (wycięcie lub otwory w otworze).

WindowInsets.waterfall

Wgłębienia reprezentujące zakrzywione obszary wodospadu. Wyświetlacz kaskadowy ma zakrzywione obszary wzdłuż krawędzi ekranu w miejscach, w których ekran zaczyna się zawijać wzdłuż boków urządzenia.

Te typy podsumowujemy za pomocą 3 „bezpiecznych” Typy wstawienia, które zapewniają, że treść nie jest zasłonięty:

Te „bezpieczne” Typy wektorów dystrybucyjnych chronią treść na różne sposoby w oparciu o bazowe elementy platformy:

  • Korzystaj z WindowInsets.safeDrawing, aby chronić treści, które nie powinny być rysowane w dowolnym interfejsie systemu. Najczęściej używa się wkładek: aby zapobiec rysunków zasłoniętych przez interfejs systemu (częściowo lub całkowicie).
  • Korzystaj z WindowInsets.safeGestures, aby chronić treści za pomocą gestów. Ten unikanie kolidowania gestów systemowych z gestami w aplikacji (np. gestami na dole ekranu). arkusze, karuzele lub gry).
  • Użyj WindowInsets.safeContent jako kombinacji atrybutów WindowInsets.safeDrawing i WindowInsets.safeGestures, aby zapewnić treści nie nakładają się na siebie ani nie nakładają się na gesty.

Konfiguracja wkładek

Aby zapewnić aplikacji pełną kontrolę nad tym, gdzie pobiera treści, postępuj zgodnie z tymi ustawieniami kroków. Jeśli nie wykonasz tych czynności, na ekranie aplikacji może wyświetlać się czarny lub jednolity kolor interfejsu użytkownika systemu lub nie są animowane synchronicznie z klawiaturą programową.

  1. Ustaw kierowanie na pakiet SDK 35 lub nowszy, aby wymuszać korzystanie z technologii Edge-to-E na Androidzie 15 i nowszych. Twoja aplikacja są wyświetlane za interfejsem systemu. Możesz dostosować interfejs aplikacji, wykonując następujące czynności: .
  2. Opcjonalnie wywołaj enableEdgeToEdge() w Activity.onCreate(), dzięki któremu możesz korzystać z aplikacji Edge w przypadku starszej wersji. Wersje Androida.
  3. Ustaw android:windowSoftInputMode="adjustResize" na stronie Aktywność AndroidManifest.xml. To ustawienie umożliwia aplikacji przyjmowanie rozmiaru programowego edytora IME w postaci wkładek, które służą do dopełniania i rozmieszczania treści. gdy edytor IME pojawia się i znika w aplikacji.

    <!-- in your AndroidManifest.xml file: -->
    <activity
      android:name=".ui.MainActivity"
      android:label="@string/app_name"
      android:windowSoftInputMode="adjustResize"
      android:theme="@style/Theme.MyApplication"
      android:exported="true">
    

Interfejsy API tworzenia wiadomości

Gdy aktywność przejmie kontrolę nad obsługą wszystkich wstawionych zestawów, możesz użyć funkcji tworzenia interfejsy API, które zapewniają, że treść nie jest zasłonięta i nie nakładają się na interfejs systemu. Te interfejsy API synchronizują też układ aplikacji z zmian wektora dystrybucyjnego.

Jest to na przykład najprostsza metoda stosowania wstawienia do treści całej aplikacji.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    enableEdgeToEdge()

    setContent {
        Box(Modifier.safeDrawingPadding()) {
            // the rest of the app
        }
    }
}

Ten fragment stosuje wstawki okna safeDrawing jako dopełnienie wokół całą zawartość aplikacji. Dzięki temu elementy interaktywne nie nakładają się na interfejs systemu, oznacza to, że żadna z aplikacji nie jest dla nich w interfejsie systemu, aby uzyskać efekt przejścia od krawędzi do krawędzi. Aby w pełni wykorzystać cały pakiet musisz dostosować, gdzie wcięcia są stosowane na ekranie po ekranie, albo poszczególne komponenty.

Wszystkie te typy wstawienia reklamy są animowane automatycznie za pomocą IME. przeniesione do API 21. Oznacza to, że wszystkie układy, w których są używane te wstawki, są również automatycznie animowany wraz ze zmianą wartości wstawienia.

Istnieją 2 główne sposoby korzystania z tych rodzajów wstawienia do dostosowania układy: modyfikatory dopełnienia i rozmiary wstawienia.

Modyfikatory dopełnienia

Modifier.windowInsetsPadding(windowInsets: WindowInsets) stosuje dla wkładek okiennych jako dopełnienia, działa w taki sam sposób jak Modifier.padding. Na przykład zasada Modifier.windowInsetsPadding(WindowInsets.safeDrawing) ma zastosowanie bezpieczne wstawki do rysowania jako dopełnienie ze wszystkich 4 stron.

Istnieje też kilka wbudowanych metod narzędzia dla najpopularniejszych typów wstawienia. Jedną z takich metod jest Modifier.safeDrawingPadding(), odpowiadająca Modifier.windowInsetsPadding(WindowInsets.safeDrawing) Występują analogiczne dla innych typów wstawienia.

Modyfikatory rozmiaru wstawionego

Poniższe modyfikatory stosują liczbę wstawionych okien przez ustawienie rozmiaru aby określić rozmiar wektorów:

Modifier.windowInsetsStartWidth(windowInsets: WindowInsets)

Stosuje stronę początkową elementów windowInsets jako szerokość (np. Modifier.width)

Modifier.windowInsetsEndWidth(windowInsets: WindowInsets)

Stosuje końcową stronę elementów windowInsets jako szerokość (np. Modifier.width)

Modifier.windowInsetsTopHeight(windowInsets: WindowInsets)

Stosuje górną stronę wstawki okna (np. Modifier.height) jako wysokość

Modifier.windowInsetsBottomHeight(windowInsets: WindowInsets)

Stosuje dolną część elementu windowInsets jako wysokość (np. Modifier.height)

Te modyfikatory są szczególnie przydatne do określania rozmiaru elementu Spacer, który zajmuje przestrzeń wektorów:

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

Wykorzystanie wbudowanej

Wstawione modyfikatory dopełnienia (windowInsetsPadding i elementy pomocnicze, takie jak safeDrawingPadding) automatycznie przetwarzają te wstawki, które są zastosowano jako dopełnienie. Zgłębiając drzewo kompozycji, zagnieżdżona wkładka z modyfikatorami dopełnienia i rozmiarem wstawienia, wiadomo, że pewna część wstawienia zostały już wykorzystane przez zewnętrzne wstawione modyfikatory dopełnienia, dlatego unikaj używając tej samej części wkładek więcej niż raz, co spowodowałoby również o wiele więcej miejsca.

Modyfikatory rozmiaru wstawienia nie używają też tej samej części wstawienia więcej niż raz jeśli wektory zostały już wykorzystane. Jednak ze względu na to, więc nie zużywają wkładek.

W efekcie zagnieżdżone modyfikatory dopełnienia automatycznie zmieniają ilość do każdego elementu kompozycyjnego zastosowano dopełnienie.

Przyglądamy się temu samemu przykładowi z elementu LazyColumn co wcześniej. LazyColumn jest obecnie rozmiar został zmieniony za pomocą modyfikatora imePadding. Ostatni element w środku LazyColumn to dostosowane do wysokości dolnej części słupków systemowych:

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

Po zamknięciu edytora IME modyfikator imePadding() nie stosuje dopełnienia, ponieważ IME nie ma wysokości. Modyfikator imePadding() nie stosuje dopełnienia, żadne wstawki nie są wykorzystywane, a wysokość Spacer będzie rozmiarem dolnych pasków systemowych.

Po otwarciu edytora IME wstawki są animowane odpowiednio do jego rozmiaru, Modyfikator imePadding() zaczyna stosować dopełnienie u dołu, aby zmienić rozmiar LazyColumn. Gdy zaczyna obowiązywać modyfikator imePadding() dopełnienie u dołu, zaczyna też zużywać tę liczbę wkładek. Dlatego wysokość elementu Spacer zaczyna się zmniejszać jako część odstępów w systemie słupki zostały już zastosowane przez modyfikator imePadding(). Gdy funkcja Modyfikator imePadding() stosuje większe dopełnienie u dołu niż słupki systemowe, wysokość Spacer wynosi zero.

Po zamknięciu IME zmiany zachodzą odwrotnie: edytor Spacer zaczyna rozwija się od wysokości 0, gdy argument imePadding() ma zastosowanie mniejsze niż dolnych pasków systemowych, aż w końcu Spacer będzie odpowiadać wysokości dolnych pasków systemowych, gdy już zostanie całkowicie animowany.

Rys. 2. Leniwa kolumna od krawędzi do krawędzi z: TextField.
.

Jest to możliwe dzięki komunikacji między wszystkimi windowInsetsPadding. Wpływ na nią może mieć kilka innych kilka sposobów.

Modifier.consumeWindowInsets(insets: WindowInsets) też używa wstawienia działa tak samo jak Modifier.windowInsetsPadding, ale nie ma zastosowania wykorzystane wstawki jako dopełnienie. Przydaje się to w połączeniu z wstawką modyfikatory rozmiaru, aby wskazać rodzeństwo, że pewna liczba wstawionych już zużyte:

Column(Modifier.verticalScroll(rememberScrollState())) {
    Spacer(Modifier.windowInsetsTopHeight(WindowInsets.systemBars))

    Column(
        Modifier.consumeWindowInsets(
            WindowInsets.systemBars.only(WindowInsetsSides.Vertical)
        )
    ) {
        // content
        Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
    }

    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.systemBars))
}

Modifier.consumeWindowInsets(paddingValues: PaddingValues) działa bardzo podobnie do wersji z argumentem WindowInsets, ale przyjmuje który ma być używany w dowolnym PaddingValues. Pozwala to określić, dzieci, jeśli dopełnienie lub odstępy są zapewniane przez inny mechanizm niż wstawiane modyfikatory dopełnienia, takie jak zwykłe Modifier.padding lub stała wysokość; odstępy:

@OptIn(ExperimentalLayoutApi::class)
Column(Modifier.padding(16.dp).consumeWindowInsets(PaddingValues(16.dp))) {
    // content
    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
}

Jeśli nieprzetworzone wstawki okien są potrzebne bez użycia, użyj metody WindowInsets bezpośrednio lub użyj wartości WindowInsets.asPaddingValues(), aby zwraca PaddingValues elementów wektorowych, na które nie ma wpływu wykorzystanie. Ze względu na poniższe zastrzeżenia wolę użyć dopełnienia wgłębień w oknach. z modyfikatorami rozmiaru i wektorami wstawiania okien, gdy tylko jest to możliwe.

Etapy wektorów i Jetpack Compose

Compose używa podstawowych interfejsów API AndroidaX do aktualizowania i animowania wektorów które wykorzystują bazowe interfejsy API platformy do zarządzania wstawieniami. Z powodu tej platformy zachowanie, wstawki mają specjalny związek z fazami jetpacka Utwórz.

Wartość wektorów jest aktualizowana po fazie kompozycji, ale przed etapie układu. Oznacza to, że odczyt wartości wkładek w kompozycji zwykle używa wartości wcięcia, która jest opóźniona o jedną klatkę. Wbudowane opisane na tej stronie modyfikatory zostały utworzone tak, aby opóźniać korzystanie z wartości funkcji są wstawiane do etapu układu, dzięki czemu wstawiane wartości są używane w tej samej ramce, w której są aktualizowane.

Animacje klawiaturowe IME w języku WindowInsets

Do kontenera przewijanego możesz zastosować Modifier.imeNestedScroll(), aby otwierać automatycznie zamyka edytor IME podczas przewijania w dół kontenera.

class WindowInsetsExampleActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        WindowCompat.setDecorFitsSystemWindows(window, false)

        setContent {
            MaterialTheme {
                MyScreen()
            }
        }
    }
}

@OptIn(ExperimentalLayoutApi::class)
@Composable
fun MyScreen() {
    Box {
        LazyColumn(
            modifier = Modifier
                .fillMaxSize() // fill the entire window
                .imePadding() // padding for the bottom for the IME
                .imeNestedScroll(), // scroll IME at the bottom
            content = { }
        )
        FloatingActionButton(
            modifier = Modifier
                .align(Alignment.BottomEnd)
                .padding(16.dp) // normal 16dp of padding for FABs
                .navigationBarsPadding() // padding for navigation bar
                .imePadding(), // padding for when IME appears
            onClick = { }
        ) {
            Icon(imageVector = Icons.Filled.Add, contentDescription = "Add")
        }
    }
}

Animacja przedstawiająca element interfejsu przewijany w górę i w dół w miejsce na klawiaturę
Rysunek 3. i animacje IME.

Wbudowana obsługa komponentów Material 3

Aby łatwo było korzystać z wielu wbudowanych funkcji kompozycyjnych Material 3, (androidx.compose.material3) obsługuje same wstawki na podstawie rozmieszczenia elementów kompozycyjnych w aplikacji. zgodnie ze specyfikacją Materiału.

Elementy kompozycyjne obsługi wstawki

Poniżej znajduje się lista Materiałów komponenty, które automatycznie obsługiwać wstawki.

Paski aplikacji

Kontenery treści

Ruszt

Domyślnie Scaffold udostępnia wektory jako parametr paddingValues, które możesz wykorzystać i wykorzystać. Scaffold nie stosuje wstawienia do treści. To Ty odpowiadasz za to. Aby np. wykorzystać te wektory z parametrem LazyColumn wewnątrz właściwości Scaffold:

Scaffold { innerPadding ->
    // innerPadding contains inset information for you to use and apply
    LazyColumn(
        // consume insets as scaffold doesn't do it by default
        modifier = Modifier.consumeWindowInsets(innerPadding),
        contentPadding = innerPadding
    ) {
        items(count = 100) {
            Box(
                Modifier
                    .fillMaxWidth()
                    .height(50.dp)
                    .background(colors[it % colors.size])
            )
        }
    }
}

Zastąp domyślne wstawki

Możesz zmienić parametr windowInsets przekazywany do funkcji kompozycyjnej na skonfigurować zachowanie funkcji kompozycyjnej. Może to być inny typ parametru wstawienie okna lub wyłączenie przez przekazanie pustej instancji: WindowInsets(0, 0, 0, 0)

Aby na przykład wyłączyć obsługę wstawienia na LargeTopAppBar ustaw parametr windowInsets na pustą instancję:

LargeTopAppBar(
    windowInsets = WindowInsets(0, 0, 0, 0),
    title = {
        Text("Hi")
    }
)

Interakcja z wektorami systemowymi widoku danych

Konieczne może być zastąpienie domyślnego wstawienia, gdy na ekranie są dostępne zarówno widoki Tworzenie kodu w tej samej hierarchii. W tym przypadku musisz wyraźnie wskazać który powinien konsumować wstawki, a który powinien je ignorować.

Jeśli na przykład Twój najbardziej zewnętrzny układ to układ Android View, przetwarzać wstawienia w systemie widoku i ignorować je podczas tworzenia wiadomości. Jeśli Twój najbardziej zewnętrzny układ jest układem kompozycyjnym, użyj funkcji w usłudze Compose i dopełnić odpowiednio elementy kompozycyjne AndroidView.

Domyślnie każde ComposeView pochłania wszystkie wstawki w WindowInsetsCompat poziom konsumpcji. Aby zmienić to domyślne działanie, ustaw ComposeView.consumeWindowInsets do false.

Materiały

. .