Sprawdzanie, czy interfejs użytkownika działa z wstawkami okna

Gdy aktywność przejmie kontrolę nad obsługą wszystkich wstawień, możesz użyć interfejsów API Compose, aby upewnić się, że treści nie są zasłonięte, a elementy, z którymi można wchodzić w interakcje, nie nakładają się na interfejs użytkownika systemu. Te interfejsy API synchronizują też układ aplikacji z zmianami w insetach.

Oto najprostsza metoda zastosowania wstawek 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 kodu stosuje wstawki okna safeDrawing jako wypełnienie wokół całej zawartości aplikacji. Dzięki temu elementy, z którymi można wchodzić w interakcję, nie będą nakładać się na interfejs systemu, ale oznacza to też, że żadna część aplikacji nie będzie narysowana za interfejsem systemu, aby uzyskać efekt obrazu sięgającego krawędzi. Aby w pełni wykorzystać cały ekran, musisz precyzyjnie określić, gdzie mają być stosowane wstawki. Możesz to zrobić na poziomie ekranu lub komponentu.

Wszystkie te typy wstawek są animowane automatycznie za pomocą animacji IME przeniesionych do interfejsu API 21. W związku z tym wszystkie układy, które korzystają z tych wstawek, są również automatycznie animowane wraz ze zmianą wartości wstawek.

Istnieją 2 podstawowe sposoby używania tych typów wstawek do dostosowywania układów kompozytowych: modyfikatory wypełnień i modyfikatory rozmiaru wstawki.

Modyfikatory wypełniania

Modifier.windowInsetsPadding(windowInsets: WindowInsets) stosuje podane w ramce zaokrąglenia jako wypełnienie, działając tak samo jak Modifier.padding. Na przykład Modifier.windowInsetsPadding(WindowInsets.safeDrawing) stosuje bezpieczne wstawione rysunki jako wypełnienie po wszystkich 4 stronach.

Dostępnych jest też kilka wbudowanych metod pomocniczych dla najczęściej używanych typów wstawek. Modifier.safeDrawingPadding() to jedna z takich metod, równoważna funkcji Modifier.windowInsetsPadding(WindowInsets.safeDrawing). Istnieją analogiczne modyfikatory dla innych typów wstawek.

Modyfikatory rozmiaru wnęki

Te modyfikatory określają ilość wstawionych okien, ustawiając rozmiar komponentu na rozmiar wstawionych okien:

Modifier.windowInsetsStartWidth(windowInsets: WindowInsets)

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

Modifier.windowInsetsEndWidth(windowInsets: WindowInsets)

Stosuje końcową stronę zawijania okna jako szerokość (jak Modifier.width).

Modifier.windowInsetsTopHeight(windowInsets: WindowInsets)

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

Modifier.windowInsetsBottomHeight(windowInsets: WindowInsets)

Dolny bok windowInsets jest stosowany jako wysokość (np. Modifier.height).

Te modyfikatory są szczególnie przydatne do ustawiania rozmiaru Spacer, który zajmuje miejsce w ramkach wstawionych:

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

Konsumpcja w ramce

Modyfikatory wkładki wypełniającej (windowInsetsPadding i elementy pomocnicze, takie jak safeDrawingPadding) automatycznie wykorzystują część wkładki, która jest stosowana jako wypełnienie. Wchodząc głębiej w drzewo kompozycji, wiesz, że wpisane modyfikatory wypełniania wgłębienia i modyfikatory rozmiaru wgłębienia wiedzą, że część wgłębień została już wykorzystana przez zewnętrzne modyfikatory wypełniania wgłębienia. Unikaj używania tej samej części wgłębień więcej niż raz, ponieważ spowodowałoby to zbyt dużo dodatkowego miejsca.

Zmienne rozmiaru wstawek również zapobiegają wielokrotnemu używaniu tej samej części wstawek, jeśli zostały one już wykorzystane. Ponieważ jednak zmieniają one bezpośrednio swój rozmiar, nie wykorzystują one samych wstawek.

W efekcie modyfikatory wypełnienia zagnieżdżonego automatycznie zmieniają ilość wypełnienia zastosowaną do każdego komponentu.

W tym samym przykładzie LazyColumn rozmiar obiektu LazyColumn jest zmieniany przez modyfikator imePadding. W elementach LazyColumn ostatni element ma wysokość odpowiadającą wysokości dolnej krawędzi pasków systemu:

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

Gdy IME jest zamknięte, modyfikator imePadding() nie stosuje wypełnienia, ponieważ IME nie ma wysokości. Ponieważ modyfikator imePadding() nie stosuje żadnych wypełnień, nie są używane żadne wstawki, a wysokość elementu Spacer będzie odpowiadać rozmiarowi dolnej strony pasków systemu.

Gdy otworzy się klawiatura, jej wstawione elementy animują się, aby dopasować się do jej rozmiaru, a modyfikator imePadding() zacznie stosować wypełnienie dolne, aby zmienić rozmiar elementu LazyColumn w miarę otwierania klawiatury. Gdy modyfikator imePadding() zacznie stosować wypełnienie dolne, zacznie też zużywać tę liczbę wstawek. W związku z tym wysokość Spacer zaczyna się zmniejszać, ponieważ część odstępów między elementami systemu została już zastosowana przez modyfikator imePadding(). Gdy modyfikator imePadding() zastosuje dopełnienie dolne większe niż paski systemowe, wysokość Spacer wynosi 0.

Gdy IME się zamyka, zmiany zachodzą w odwrotnej kolejności: gdy imePadding() jest mniejsza niż dolna krawędź pasków systemu, Spacer zaczyna się rozszerzać od wysokości 0, aż w końcu osiągnie wysokość odpowiadającą dolnej krawędzi pasków systemu, gdy IME zostanie całkowicie zamknięte.Spacer

Rysunek 2. Kolumna z automatycznym wypełnianiem od krawędzi do krawędzi z wartością TextField.

To zachowanie jest realizowane przez komunikację między wszystkimi modyfikatorami windowInsetsPadding i może być modyfikowane na kilka innych sposobów.

Modifier.consumeWindowInsets(insets: WindowInsets) również wykorzystuje wstawione elementy w taki sam sposób jak Modifier.windowInsetsPadding, ale nie stosuje wstawionych elementów jako wypełnienia. Jest to przydatne w połączeniu z modyfikatorami rozmiaru wgłębienia, aby wskazać elementom nadrzędnym, że pewna liczba wgłębień została już wykorzystana:

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 dowolną wartość PaddingValues. Jest to przydatne, gdy chcesz poinformować dzieci, że wypełnienie lub odstępy są zapewniane przez inny mechanizm niż modyfikatory wbudowanego wypełniania, takie jak zwykłe Modifier.padding lub odstępy o stałej wysokości:

Column(Modifier.padding(16.dp).consumeWindowInsets(PaddingValues(16.dp))) {
    // content
    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
}

W przypadku, gdy potrzebne są nieprzetworzone wstawki okna, użyj bezpośrednio wartości WindowInsets lub polecenia WindowInsets.asPaddingValues(), aby zwrócić PaddingValues wstawek, które nie są objęte przetwarzaniem. Ze względu na poniższe zastrzeżenia zalecamy jednak, aby w miarę możliwości używać modyfikatorów wypełniania okna i modyfikatorów rozmiaru okna.

Ramki i fazy Jetpack Compose

Compose używa podstawowych interfejsów API AndroidX do aktualizowania i animowania wgłębień, które korzystają z podstawowych interfejsów API platformy do zarządzania wgłębieniami. Ze względu na to zachowanie platformy wstawki mają szczególny związek z etazami Jetpacka Compose.

Wartości wstawek są aktualizowane po fazie tworzenia kompozycji, ale przed fazą układu. Oznacza to, że odczyt wartości wstawek w kompozycji wykorzystuje zazwyczaj wartość wstawek, która jest o 1 klatka późniejsza. Wbudowane modyfikatory opisane na tej stronie są zaprojektowane tak, aby opóźniać używanie wartości w ramkach do fazy układu. Dzięki temu wartości w ramkach są używane w tym samym ujęciu, w którym są aktualizowane.