Wiadomości o usługach

Nowości w Jetpack Compose w kwietniu 2026 r.

Czas czytania: 6 minut
Wyświetl profil Meghan Mehty
Meghan Mehta Przedstawiciel ds. kontaktu z deweloperami Androida

Dziś wersja Jetpack Compose z kwietnia 2026 r. jest stabilna. Ta wersja zawiera moduły podstawowe Compose w wersji 1.11 (pełne mapowanie listy materiałów), narzędzia do debugowania wspólnych elementów, zdarzenia trackpada i inne funkcje. Mamy też kilka eksperymentalnych interfejsów API, które chcielibyśmy, abyś wypróbował(-a) i przekazał(-a) nam swoją opinię.

Aby korzystać z dzisiejszej wersji, zaktualizuj wersję Compose BOM do:

implementation(platform("androidx.compose:compose-bom:2026.04.01"))

Zmiany w Compose 1.11.0

Wykonywanie korutyn w testach

Wprowadzamy ważną zmianę w sposobie, w jaki Compose obsługuje czas testu. Po okresie przystąpienia do testów ogłoszonym w Compose 1.10 interfejsy API do testowania w wersji 2 są teraz domyślne, a interfejsy API w wersji 1 zostały wycofane. Kluczową zmianą jest zmiana domyślnego dyspozytora testów. Interfejsy API w wersji 1 korzystały z UnconfinedTestDispatcher, które natychmiast wykonywało korutyny, a interfejsy API w wersji 2 używają StandardTestDispatcher. Oznacza to, że gdy w testach uruchamiany jest współprogram, jest on teraz umieszczany w kolejce i nie jest wykonywany, dopóki nie zostanie przesunięty zegar wirtualny.

Dzięki temu lepiej odzwierciedlisz warunki produkcyjne, skutecznie wyeliminujesz sytuacje wyścigu i sprawisz, że zestaw testów będzie znacznie bardziej niezawodny i mniej podatny na błędy.

Aby mieć pewność, że testy są zgodne ze standardowym działaniem współprogramów, i uniknąć problemów ze zgodnością w przyszłości, zdecydowanie zalecamy przeniesienie zestawu testów. Zapoznaj się z naszym kompleksowym przewodnikiem po migracji, w którym znajdziesz mapowania interfejsów API i częste rozwiązania problemów.

Ulepszenia elementów udostępnionych i narzędzia do animacji

Dodaliśmy też przydatne wizualne narzędzia do debugowania elementów udostępnionych i Modifier.animatedBounds. Możesz teraz dokładnie zobaczyć, co się dzieje w tle – np. granice docelowe, trajektorie animacji i liczbę znalezionych dopasowań – co znacznie ułatwia wykrycie, dlaczego przejście może nie działać zgodnie z oczekiwaniami. Aby użyć nowych narzędzi, wystarczy otoczyć element SharedTransitionLayout kompozycją LookaheadAnimationVisualDebugging. 

LookaheadAnimationVisualDebugging(
    overlayColor = Color(0x4AE91E63),
    isEnabled = true,
    multipleMatchesColor = Color.Green,
    isShowKeylabelEnabled = false,
    unmatchedElementColor = Color.Red,
) {
    SharedTransitionLayout {
        CompositionLocalProvider(
            LocalSharedTransitionScope provides this,
        ) {
            // your content
        }
    }
}

Zdarzenia związane z trackpadem

Ulepszyliśmy obsługę pisania na trackpadach, takich jak wbudowane trackpady laptopów, trackpady dołączane do tabletów czy zewnętrzne/wirtualne trackpady. Podstawowe zdarzenia trackpada będą teraz ogólnie traktowane jako zdarzenia PointerType.Mouse, co spowoduje, że zachowanie myszy i trackpada będzie lepiej odpowiadać oczekiwaniom użytkowników. Wcześniej te zdarzenia na trackpadzie były interpretowane jako fałszywe dotknięcia ekranu przez palce PointerType.Touch, co powodowało zamieszanie wśród użytkowników. Na przykład kliknięcie i przeciągnięcie na trackpadzie spowoduje przewijanie zamiast zaznaczania. W najnowszej wersji Compose zmieniliśmy typ wskaźnika tych zdarzeń, więc klikanie i przeciąganie za pomocą trackpada nie będzie już powodować przewijania.

Dodaliśmy też obsługę bardziej skomplikowanych gestów na trackpadzie rozpoznawanych przez platformę od interfejsu API w wersji 34, w tym przesunięć dwoma palcami i uszczypnięć. Te gesty są automatycznie rozpoznawane przez komponenty takie jak Modifier.scrollable i Modifier.transformable, co poprawia ich działanie na trackpadach.

Zmiany te poprawiają działanie trackpadów w przypadku wbudowanych komponentów. Usunęliśmy zbędne opóźnienie dotyku, wprowadziliśmy bardziej intuicyjny gest przeciągania i upuszczania, dwukrotne i trzykrotne kliknięcie w polach tekstowych oraz menu kontekstowe w polach tekstowych w stylu komputerów stacjonarnych.

Aby przetestować działanie trackpada, udostępniliśmy nowe interfejsy API do testowania z performTrackpadInput,, które umożliwiają sprawdzanie działania aplikacji podczas korzystania z trackpada. Jeśli masz niestandardowe detektory gestów, sprawdź ich działanie na różnych typach urządzeń wejściowych, w tym na ekranach dotykowych, myszach, trackpadach i rysikach, oraz upewnij się, że obsługują kółka przewijania myszy i gesty na trackpadzie.

beforeAndAfter.webp

Domyślne ustawienia hosta kompozycji (środowisko wykonawcze Compose)

Wprowadziliśmy HostDefaultProvider, LocalHostDefaultProvider, HostDefaultKey i ViewTreeHostDefaultKey, aby udostępniać usługi na poziomie hosta bezpośrednio za pomocą compose-runtime. Eliminuje to konieczność korzystania z compose-ui w przypadku wyszukiwania w bibliotekach, co zapewnia lepszą obsługę Kotlin Multiplatform. Aby połączyć te wartości z drzewem kompozycji, autorzy bibliotek mogą użyć compositionLocalWithHostDefaultOf do utworzenia CompositionLocal, które rozwiązuje wartości domyślne z hosta.

Podgląd kodów towarzyszących

Niestandardowe podglądy w Android Studio to nowa funkcja, która pozwala dokładnie określić sposób wyświetlania treści podglądu Compose.

Implementując interfejs PreviewWrapperProvider i stosując nową adnotację @PreviewWrapper, możesz łatwo wstrzykiwać niestandardową logikę, np. stosować określony Theme. Adnotację można zastosować do funkcji z adnotacjami @Composable i @Preview lub @MultiPreview, co zapewnia ogólne, łatwe w użyciu rozwiązanie, które działa w przypadku funkcji w wersji podglądowej i znacznie ogranicza powtarzający się kod.

class ThemeWrapper: PreviewWrapperProvider {
    @Composable
    override fun Wrap(content: @Composable (() -> Unit)) {
        JetsnackTheme {
            content()
        }
    }
}


@PreviewWrapper(ThemeWrapper::class)
@Preview
@Composable
private fun ButtonPreview() {
    // JetsnackTheme in effect
    Button(onClick = {}) {
        Text(text = "Demo")
    }
}

Wycofania i usunięcia

  • Jak ogłosiliśmy w poście na blogu o Compose 1.10, wycofujemy Modifier.onFirstVisible(). Jego nazwa często prowadziła do nieporozumień, zwłaszcza w przypadku układów leniwych, w których wywoływał się wielokrotnie podczas przewijania. Zalecamy przejście na Modifier.onVisibilityChanged(), które umożliwia bardziej precyzyjne ręczne śledzenie stanów widoczności dostosowane do Twoich konkretnych wymagań.
  • Flaga ComposeFoundationFlags.isTextFieldDpadNavigationEnabled została usunięta, ponieważ nawigacja za pomocą pada kierunkowego w przypadku TextFields jest teraz zawsze domyślnie włączona. Nowe działanie zapewnia, że zdarzenia z pada kierunkowego na gamepadzie lub pilocie do telewizora najpierw przesuwają kursor w danym kierunku. Fokus może przejść do innego elementu tylko wtedy, gdy kursor dotrze do końca tekstu.

Nadchodzące interfejsy API

W nadchodzącej wersji Compose 1.12.0 wartość compileSdk zostanie zaktualizowana do compileSdk 37. Wymaganie to będzie dziedziczone przez AGP 9 oraz wszystkie aplikacje i biblioteki, które są zależne od Compose. Zalecamy korzystanie z najnowszych wersji, ponieważ Compose szybko wprowadza nowe compileSdks, aby zapewnić dostęp do najnowszych funkcji Androida. Więcej informacji o tym, która wersja AGP jest obsługiwana w przypadku różnych poziomów API, znajdziesz w dokumentacji. 

W Compose 1.11.0 wprowadziliśmy te interfejsy API jako @Experimental. Czekamy na Twoje opinie, gdy będziesz ich używać w swoich aplikacjach. Pamiętaj, że @Experimental APIs są udostępniane do wczesnej oceny i przekazywania opinii. W przyszłych wersjach mogą ulec znacznym zmianom lub zostać usunięte.

Style (eksperymentalne)

Wprowadzamy nowy eksperymentalny interfejs API do stylizowania. Style API to nowy paradygmat dostosowywania elementów wizualnych komponentów, który tradycyjnie był realizowany za pomocą modyfikatorów. Został on zaprojektowany tak, aby umożliwić głębsze i łatwiejsze dostosowywanie dzięki udostępnianiu zestawu standardów właściwości, które można stylizować za pomocą prostego stylu opartego na stanie i animowanych przejść. Dzięki temu nowemu interfejsowi API widzimy już obiecujące korzyści w zakresie skuteczności. Planujemy wprowadzić style w komponentach Material, gdy interfejs Style API będzie stabilny.

Oto podstawowy przykład zastępowania tła stylu stanu naciśnięcia:

@Composable
fun LoginButton(modifier: Modifier = Modifier) {
    Button(
        onClick = {
            // Login logic
        },
        modifier = modifier,
        style = {
            background(
                Brush.linearGradient(
                    listOf(lightPurple, lightBlue)
                )
            )
            width(75.dp)
            height(50.dp)
            textAlign(TextAlign.Center)
            externalPadding(16.dp)

            pressed {
                background(
                    Brush.linearGradient(
                        listOf(Color.Magenta, Color.Red)
                    )
                )
            }
        }
    ){
        Text(
            text = "Login",
        )
    }
}
styles.webp

Zapoznaj się z dokumentacją i zgłaszaj błędy tutaj.

MediaQuery (eksperymentalne)

Nowy interfejs mediaQuery API zapewnia deklaratywny i wydajny sposób dostosowywania interfejsu do środowiska. Upraszcza złożone pobieranie informacji do prostych warunków w UiMediaScope, dzięki czemu rekompozycja następuje tylko wtedy, gdy jest to konieczne.

Dzięki obsłudze szerokiej gamy sygnałów środowiskowych – od możliwości urządzenia, takich jak typy klawiatur i precyzja wskaźnika, po stany kontekstowe, takie jak rozmiar okna i stan zabezpieczeń – możesz tworzyć bardzo elastyczne funkcje. Wydajność jest wbudowana w derivedMediaQuery, aby obsługiwać aktualizacje o wysokiej częstotliwości, a możliwość zastępowania zakresów sprawia, że testowanie i podgląd są bezproblemowe w różnych konfiguracjach sprzętowych. Wcześniej, aby uzyskać dostęp do niektórych właściwości urządzenia, np. informacji o tym, czy urządzenie jest w trybie stołowym, trzeba było napisać dużo kodu: 

@Composable
fun isTabletopPosture(
    context: Context = LocalContext.current
): Boolean {
    val windowLayoutInfo by
        WindowInfoTracker
            .getOrCreate(context)
            .windowLayoutInfo(context)
            .collectAsStateWithLifecycle(null)

    return windowLayoutInfo.displayFeatures.any { displayFeature ->
        displayFeature is FoldingFeature &&
            displayFeature.state == FoldingFeature.State.HALF_OPENED &&
            displayFeature.orientation == FoldingFeature.Orientation.HORIZONTAL
    }
}

@Composable
fun VideoPlayer() {
    if(isTabletopPosture()) {
        TabletopLayout()
    } else {
        FlatLayout()
    }
}

Teraz za pomocą funkcji UIMediaQuery możesz dodać składnię mediaQuery, aby wysyłać zapytania o właściwości urządzenia, np. czy jest ono w trybie stołowym:

@OptIn(ExperimentalMediaQueryApi::class)
@Composable
fun VideoPlayer() {
    if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) {
        TabletopLayout()
    } else {
        FlatLayout()
    }
}

Zapoznaj się z dokumentacją i zgłaszaj błędy tutaj.

Siatka (eksperymentalna)

Grid to nowy, zaawansowany interfejs API do tworzenia złożonych układów dwuwymiarowych w Jetpack Compose. Chociaż Row i Column świetnie sprawdzają się w przypadku projektów liniowych, Grid zapewnia kontrolę strukturalną potrzebną w przypadku architektury na poziomie ekranu i złożonych komponentów bez obciążenia związanego z listą przewijaną. Grid umożliwia zdefiniowanie układu za pomocą ścieżek, przerw i komórek, oferując znane opcje rozmiaru, takie jak Dp, wartości procentowe, rozmiary treści wewnętrznych i elastyczne jednostki „Fr”.

@OptIn(ExperimentalGridApi::class)
@Composable
fun GridExample() {
    Grid(
        config = {
            repeat(4) { column(0.25f) }
            repeat(2) { row(0.5f) }
            gap(16.dp)
        }
    ) {
        Card1(modifier = Modifier.gridItem(rowSpan = 2)
        Card2(modifier = Modifier.gridItem(colmnSpan = 3)
        Card3(modifier = Modifier.gridItem(columnSpan = 2)
        Card4()
    }
}

Możesz umieszczać elementy automatycznie lub rozciągać je na wiele wierszy i kolumn, aby uzyskać większą precyzję. Co najważniejsze, jest ona bardzo elastyczna – możesz dynamicznie zmieniać konfigurację ścieżek i zakresów siatki, aby dostosowywać ją do stanu urządzenia, np. trybu stołowego lub zmiany orientacji. Dzięki temu interfejs użytkownika będzie świetnie wyglądać na różnych urządzeniach.

Grid.gif

Zapoznaj się z dokumentacją i zgłaszaj błędy tutaj. 

FlexBox (eksperymentalny)

FlexBox to kontener układu zaprojektowany z myślą o wysokiej wydajności i adaptacyjnych interfejsach. Zarządza rozmiarem elementów i rozmieszczeniem przestrzeni na podstawie dostępnych wymiarów kontenera. Umożliwia wykonywanie złożonych zadań, takich jak zawijanie (wrap) i wyrównywanie elementów względem wielu osi (justifyContent, alignItems, alignContent). Pozwala na powiększanie (grow) i zmniejszanie (shrink) elementów w celu wypełnienia kontenera. 

@OptIn(ExperimentalFlexBoxApi::class)
fun FlexBoxWrapping(){
    FlexBox(
        config = {
            wrap(FlexWrap.Wrap)
            gap(8.dp)
        }
    ) {
        RedRoundedBox()
        BlueRoundedBox()
        GreenRoundedBox(modifier = Modifier.width(350.dp).flex { grow(1.0f) })
        OrangeRoundedBox(modifier = Modifier.width(200.dp).flex { grow(0.7f) })
        PinkRoundedBox(modifier = Modifier.width(200.dp).flex { grow(0.3f) })
    }
}
AnimationGif.gif

Zapoznaj się z dokumentacją i zgłaszaj błędy tutaj.

Nowa implementacja SlotTable (eksperymentalna)

Wprowadziliśmy nową implementację elementu SlotTable, która jest domyślnie wyłączona w tej wersji.SlotTable to wewnętrzna struktura danych, której środowisko wykonawcze Compose używa do śledzenia stanu hierarchii kompozycji, śledzenia unieważnień i ponownych kompozycji, przechowywania zapamiętanych wartości oraz śledzenia wszystkich metadanych kompozycji w czasie działania. Ta nowa implementacja ma na celu poprawę wydajności, zwłaszcza w przypadku losowych zmian.

Aby wypróbować nową funkcję SlotTable, włącz ComposeRuntimeFlags.isLinkBufferComposerEnabled. 

Zacznij kodować już dziś!

W Jetpack Compose jest wiele nowych, ciekawych interfejsów API, a wkrótce pojawią się kolejne. To najlepszy moment, aby przejść na Jetpack Compose. Jak zawsze, cenimy Twoje opinie i propozycje dotyczące funkcji (zwłaszcza tych, które są jeszcze w @Experimental fazie rozwoju) – możesz je przesyłać tutaj. Miłego pisania!

Autorzy:
Czytaj dalej