Wiadomości o usługach

Nowości w Jetpack Compose w sierpniu 2026 r.

Czas czytania: 5 minut
Wyświetl profil Nicka Butchera
Nick Butcher Menedżer produktu

Dziś opublikowaliśmy stabilną wersję Jetpack Compose z sierpnia 2026 r. Ta wersja wprowadza wersję 1.12 w podstawowych modułach Compose (pełne mapowanie BOM), wprowadzając zaawansowane interfejsy API do obsługi grafiki, takie jak gradienty siatkowe i obsługa szerokiej gamy kolorów (WCG), funkcje układu strukturalnego, takie jak nazwane obszary w Grid, bezproblemową integrację z Menedżerem danych logowania Androida oraz znaczące ulepszenia w zakresie testowania i wydajności.

Aby zaktualizować projekt do dzisiejszej wersji, zaktualizuj wersję Compose BOM do 2026.08.00:

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

Zmiany powodujące niezgodność

  • AGP i pakiet SDK do kompilacji: Compose 1.12 aktualizuje pakiet SDK do kompilacji do interfejsu API 37, co wymaga co najmniej AGP 9.1.2. Przypominamy, że Compose zawsze będzie kierować reklamy na najnowszy pakiet compileSdk. Więcej informacji o tej zmianie znajdziesz tutaj.
  • Modifier.onFirstVisible() Funkcja jest wycofana: przejdź na Modifier.onVisibilityChanged(), która zapewnia dokładniejsze śledzenie progu widoczności.

Grafika

Gradienty siatkowe

W Compose 1.12 wprowadziliśmy MeshGradientPainter, aby ułatwić Ci tworzenie wielopunktowych gradientów kolorów.

meshGradient.gif
val rows = 1
val columns = 1

val gradientPainter = remember {
    MeshGradientPainter(rows, columns) {
        // Parameters: row, column, position, color
        setVertex(0, 0, Offset(0f, 0f), Color.Red)     // Top-Left
        setVertex(0, 1, Offset(1f, 0f), Color.Blue)    // Top-Right
        setVertex(1, 0, Offset(0f, 1f), Color.Green)   // Bottom-Left
        setVertex(1, 1, Offset(1f, 1f), Color.Yellow)  // Bottom-Right
    }
}

Box(
    modifier = modifier
        .aspectRatio(16/9f)
        .fillMaxWidth()
        .paint(gradientPainter)
)

Więcej informacji i przykładów znajdziesz w dokumentacji.

Szeroka gama kolorów i obsługa HDR

Nowoczesne wyświetlacze oferują większą wierność kolorów i wyższy zakres dynamiczny. W Compose 1.12 włączyliśmy pełną obsługę szerokiej gamy kolorów (P3) i renderowania HDR w grafice, malowaniu i shaderach Compose. Kolory zdefiniowane w przestrzeniach kolorów innych niż sRGB (np. Display P3) są zachowywane podczas renderowania na platformie bez przycinania kolorów. Jeśli kolory korzystają z nieobsługiwanej przestrzeni kolorów (np. CieXyz, CieLab lub Oklab), zależą od przestrzeni kolorów w nieobsługiwanej wersji Androida (np. Bt2020Hlg w Androidzie 13 i starszych wersjach) lub jeśli aplikacja działa w Androidzie 9 (API 28) i starszych wersjach, bezpiecznie powrócą do sRGB.

Inne ważne zmiany:

  • Do warstw GraphicsLayer i Modifier.graphicsLayer dodano LayerOutsets, którego możesz użyć, aby zwiększyć wizualne granice warstwy poza jej zmierzony rozmiar. Zastosuj LayerOutsets, aby uniknąć domyślnego zachowania clipToBounds, gdy warstwa jest przenoszona do bufora poza ekranem.

Style

Na konferencji Google I/O przedstawiliśmy naszą wstępną wizję interfejsu API stylów Compose, czyli ujednoliconego i wydajnego sposobu na stylowanie komponentów. Od tego czasu rozwijamy architekturę bazową, aby zagwarantować ścisłe bezpieczeństwo typów i przewidywalną poprawność oraz umożliwić tworzenie niestandardowych systemów projektowania. 

Aby mieć pewność, że ta podstawowa warstwa jest prawidłowa, interfejs API pozostanie w wersji eksperymentalnej i możesz spodziewać się w nim zmian powodujących niezgodność wsteczną. 

Optymalizacje w czasie działania

Keyed SideEffect Overload

SideEffect obsługuje teraz kluczowe argumenty, które umożliwiają wywoływanie jednorazowych efektów ubocznych za każdym razem, gdy zmieniają się określone klucze. Może to prowadzić do lepszej wydajności w porównaniu z używaniem LaunchedEffect lub DisposableEffect , gdy nie potrzebujesz współprogramu ani bloku dispose. SideEffect jest do 90% szybszy niż LaunchedEffect i o około 20% szybszy niż DisposableEffect. Pamiętaj, że funkcja SideEffect działa przed funkcjami DisposableEffect i LaunchedEffect, więc zachowaj ostrożność podczas przenoszenia istniejących efektów do tego interfejsu API, zwłaszcza w przypadku funkcji LaunchedEffects, które muszą być wysyłane, aby rozpocząć działanie po zakończeniu bieżącej klatki. 

@Composable
fun AnalyticsTracker(userId: String, screenName: String) {
    SideEffect(key1 = userId, key2 = screenName) {
        analytics.logScreenView(userId, screenName)
    }
}

Animacja

Interaktywne przejścia dwuetapowe

  • Nowe funkcje kompozycyjne: DeferredAnimatedContent i DeferredAnimatedVisibility umożliwiają tworzenie atrakcyjnych dwuetapowych przejść, np. do śledzenia gestu przewidywanego przejścia wstecz.
  • Ręczne sterowanie animacją: w fazie odroczonej przejścia właściwości animowane (np.skala lub przesunięcie) można teraz ręcznie modyfikować w czasie rzeczywistym (np. śledzić gest przesuwania).
  • Płynne przekazanie: po zakończeniu fazy odroczonej silnik przejścia przejmuje kontrolę i przeprowadza płynne przekazanie, w tym przeniesienie prędkości, do automatycznego przejścia.
  • Obsługa udostępnionych elementów: nowy atrybut permitTransformDuringDeferredTransition w SharedContentConfig określa, czy udostępnione elementy mają się wizualnie przekształcać wraz z kontenerami nadrzędnymi w fazie odroczonego przejścia.
val state = remember { DeferredTransitionState(initialScreen) }
val transition = rememberDeferredTransition(state)

if (predictiveBackInProgress) {
    state.defer(targetScreen)
} else {
    state.animateTo(targetScreen)
}

transition.DeferredAnimatedContent(
    targetState = targetScreen,
    mutableTransformSpec = {
       MutableContentTransform {
           // Manually manipulate properties during the deferred phase
           initialContentTransform { scale = swipeProgress }
       }
    }
) { screen ->
    ScreenContent(screen)
}

Poniżej znajdziesz 2 wersje demonstracyjne przypadków użycia, w których animacja sterowana gestami jest przekazywana do animacji wyzwalanej:

colorCards.gif

Integracja tekstu, danych wejściowych i platformy

Formatowanie tekstu z możliwością edycji

Nowe interfejsy API oferują formatowanie tekstu sformatowanego w przypadku edytowalnego tekstu w BasicTextField. Możesz teraz automatycznie stosować i modyfikować formatowanie znaków i akapitów w tekście za pomocą SpanStyle i ParagraphStyle za pomocą nowej metody addStyle() w zakresie TextFieldBuffer (np. w textFieldState.edit { ... } lub InputTransformation). Dodatkowo TextFieldBuffer udostępnia interfejsy API getSpanStyles() i getParagraphStyles(), które zwracają obiekty TrackedRange, co umożliwia odczytywanie, aktualizowanie i usuwanie zastosowanych stylów. Aby uzupełnić tworzenie formatowania, TextFieldState udostępnia teraz właściwość textStyles tylko do odczytu, która umożliwia wysyłanie zapytań o aktywne style w zakresach, a TextFieldBuffer udostępnia originalTextStyles, aby sprawdzić stan formatowania przed edycją. Formatowanie tekstu i niestandardowe adnotacje są zachowywane po zmianie konfiguracji.

val state = rememberTextFieldState("Formatted text in Compose 1.12")

// Apply bold and color styles to a range of text
state.edit {
    addStyle(
        SpanStyle(fontWeight = FontWeight.Bold, color = Color.Blue),
        start = 0,
        end = 9
    )
}

// Query active styles from TextFieldState
val currentStyles = state.textStyles

Wybieranie tekstu

Nowy interfejs SelectionState API umożliwia programowe sterowanie wyborem tekstu w SelectionContainer i jego obserwację. Podniesienie obiektu SelectionState za pomocą rememberSelectionState() i przekazanie go do SelectionContainer powoduje udostępnienie selectedTexts jako reaktywnej listy AnnotatedStrings oraz udostępnia metody takie jak selectAll(), clear(), select(TextRange) i extendSelectionByWord().

Dodatkowo użyj getSelectableTexts(), aby pobrać wszystkie elementy tekstowe, które można wybrać, w kolejności układu i wybrać tekst w komponentach SelectionContainer za pomocą zakresu globalnego. 

@Composable
fun ProgrammaticSelectionExample() {
    val selectionState = rememberSelectionState()

    Column {
        Button(
            onClick = { selectionState.selectAll() },
            modifier = Modifier.disableSelectionClearOnTap()
        ) {
            Text("Select All")
        }

        SelectionContainer(state = selectionState) {
            Text("Text content to be selected programmatically.")
        }
    }
}

Integracja z Credential Managerem

Pola tekstowe Compose są teraz natywnie zintegrowane z usługą Credential Manager na Androidzie (API w wersji 34 lub nowszej) za pomocą platformy autouzupełniania (w przypadku API w wersji starszej niż 34 obsługę zapewnia androidx.credentials library). Dzięki dołączeniu nowej właściwości semantycznej credentialRequest z wartością CredentialRequestData pola tekstowe mogą wyświetlać prośby o klucze dostępu, zapisane dane logowania lub logowanie bezpośrednio w procesie danych wejściowych użytkownika.

@Composable
fun LoginField(textFieldState: TextFieldState) {
    val credentialData = remember {
        CredentialRequestData(
            // Specify Credential Manager request options
        )
    }

    BasicTextField(
        state = textFieldState,
        modifier = Modifier.semantics {
            credentialRequest = credentialData
        }
    )
}

Inne ważne zmiany:

  • Obsługa ustawień wariacji czcionek w czcionkach do pobrania.
  • Włączono automatyczne przewijanie podczas przeciągania zaznaczonego tekstu poza obszar widoczny w SelectionContainer.
  • Dodano obsługę automatycznych dźwięków interakcji (kliknięć i nawigacji za pomocą fokusu) w komponentach Compose, a także nowy komponent SoundEffectOnInteraction, który umożliwia rezygnację z tej funkcji. Pamiętaj, że w wyniku tej zmiany odbiorniki kliknięć semantycznych muszą być teraz wywoływane z wątku głównego, co może mieć wpływ na niewielką liczbę przypadków testowych.
  • KeyboardType obejmuje teraz Date, Time, DateTime i SignedDecimal.
  • BasicSecureTextField domyślnie używa teraz TextObfuscationMode.System, a RevealLastTyped jest bezwzględnym zastąpieniem.

Ulepszenia układu

Nazwane obszary w układzie siatki

Tworzenie złożonych układów 2D jest teraz łatwiejsze dzięki nazwom obszarów w komponencie @Experimental Siatka. Zamiast zarządzać indeksami kolumn i wierszy w różnych elementach, możesz zdefiniować regiony semantyczne w GridConfigurationScope i umieszczać komponenty według nazwy obszaru.

@OptIn(ExperimentalGridApi::class)
@Composable
fun DashboardLayout() {
    Grid(
        config = {
            area("header", row = 0, column = 0, rowSpan = 1, columnSpan = 2)
            area("sidebar", row = 1, column = 0)
            area("content", row = 1, column = 1)
            gap(16.dp)
        }
    ) {
        HeaderSection(modifier = Modifier.gridItem(areaId = "header"))
        NavigationSidebar(modifier = Modifier.gridItem(areaId = "sidebar"))
        MainContentView(modifier = Modifier.gridItem(areaId = "content"))
    }
}

Więcej informacji znajdziesz w dokumentacji.

Wydajność

Jak w przypadku każdej wersji, nadal inwestujemy w wydajność Compose, aby zapewnić, że framework pomoże Ci tworzyć piękne i wydajne aplikacje. W tej wersji skupiliśmy się na poprawie wydajności uruchamiania i obecnie widzimy, że czas do pierwszego wyświetlenia (czas potrzebny aplikacji na wygenerowanie pierwszej klatki) jest porównywalny z wyświetleniami w naszych testach porównawczych.

timetoinitialdisplay@2x _v2.png

Ulepszenia testów i narzędzi

Synchronizacja testu

W Compose 1.12 wprowadziliśmy nowe interfejsy API do testowania, które skracają czas wykonywania testów i eliminują niestabilność podczas próbkowania stanu:

  • hasPendingWork: pasywnie sprawdza, czy interfejs ma oczekujące zadania, nie przesuwając zegara. Jest to idealne rozwiązanie w przypadku ręcznych pętli animacji.
  • runWithoutImplicitWait: tymczasowo wyłącza synchronizację niejawną podczas przechodzenia przez klatki zegara ręcznego (np. testy animacji).
@Test
fun testAnimationStateFast() {

composeTestRule.mainClock.autoAdvance = false
    
    while (composeTestRule.hasPendingWork()) {
        composeTestRule.mainClock.advanceTimeByFrame()
        composeTestRule.waitForIdle()
        
        composeTestRule.runOnUiThread {
            composeTestRule.runWithoutImplicitWait {
                // This is most effective when querying multiple nodes in a single frame. 
                // It prevents the redundant synchronization overhead that would 
                // otherwise occur on every individual query.
                val box1 = composeTestRule.onNodeWithTag("Box1").fetchSemanticsNode()
                val box2 = composeTestRule.onNodeWithTag("Box2").fetchSemanticsNode()
                
                assertThat(box1.boundsInRoot.right).isAtMost(box2.boundsInRoot.left)
            }
        }
    }
}

Inne ważne zmiany:

  • Interfejs captureToImage API umożliwia teraz przechwytywanie wyskakującego okienka lub okna dialogowego wraz z jego elementem zakotwiczającym w jednej mapie bitowej.
  • Dodano onRootWithViewInteraction, aby ograniczyć zakres wyszukiwania semantycznego w Compose do konkretnych widoków Androida. Upraszcza to testowanie hybrydowych interfejsów, np. RecyclerViews, bez konieczności stosowania unikalnych tagów testowych w kodzie produkcyjnym.
  • Adnotacje @PreviewWrapper można teraz stosować do niestandardowych klas @MultiPreview, co umożliwia ponowne wykorzystywanie konfiguracji podglądu (np. niestandardowych motywów) w wielu komponentach.

Miłego tworzenia!

Compose 1.12 sprawia, że tworzenie aplikacji jest łatwiejsze i bardziej ekspresyjne niż kiedykolwiek wcześniej dzięki gradientom siatkowym, obsłudze szerokiej gamy kolorów, czcionkom zmiennym do pobrania, integracji z Credential Managerem i szybszym narzędziom do testowania. Jak zawsze cenimy Twoją opinię, więc podziel się z nami swoimi uwagami na temat tych zmian lub tym, co chcesz zobaczyć w przyszłości, na naszym trackerze problemów. Miłego pisania!

Czytaj dalej