Wiadomości o usługach

Co nowego w Jetpack Compose w sierpniu 2026 r.

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

Dziś ogłaszamy, że wersja Jetpack Compose z sierpnia 2026 r. jest stabilna. Ta wersja zawiera wersję 1.12 w podstawowych modułach Compose (pełne mapowanie BOM), wprowadza bogate wizualne interfejsy API, 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 Credential Managerem Androida oraz znaczące ulepszenia testowania i wydajności.

Aby zaktualizować projekt do dzisiejszej wersji, uaktualnij 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 compileSdk do API 37, co wymaga co najmniej AGP 9.1.2. Przypominamy, że Compose zawsze będzie kierować się najnowszym compileSdk. Więcej informacji o tej zmianie znajdziesz tutaj.
  • Modifier.onFirstVisible() został wycofany: przejdź na Modifier.onVisibilityChanged(), który zapewnia dokładniejsze śledzenie progu widoczności.

Grafika

Gradienty siatkowe

Compose 1.12 wprowadza MeshGradientPainter, który pomaga tworzyć wielopunktowe, organiczne gradienty 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łady znajdziesz w dokumentacji.

Obsługa szerokiej gamy kolorów i HDR

Nowoczesne wyświetlacze oferują rozszerzoną wierność kolorów i większy zakres dynamiczny. W Compose 1.12 włączono 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 używają nieobsługiwanej przestrzeni kolorów (np. CieXyz, CieLab lub Oklab), opierają się na przestrzeni kolorów w nieobsługiwanej wersji Androida (np. Bt2020Hlg w Androidzie 13 i starszych) lub jeśli aplikacja działa w Androidzie 9 (API 28) i starszych, bezpiecznie powrócą do sRGB.

Inne ważne zmiany:

  • LayerOutsets dodano do GraphicsLayer i Modifier.graphicsLayer, którego można użyć do zwiększenia wizualnych granic warstwy poza jej zmierzony rozmiar. Zastosuj LayerOutsets, aby uniknąć domyślnego zachowania clipToBounds, gdy warstwa jest promowana do bufora poza ekranem.

Style

Podczas Google I/O przedstawiliśmy naszą wstępną wizję interfejsu Styles API w Compose – ujednoliconego i wydajnego sposobu stylizowania komponentów. Od tego czasu kontynuowaliśmy budowanie podstawowej architektury, aby zagwarantować ścisłe zabezpieczenia wpisywania i przewidywalną poprawność oraz obsługę tworzenia niestandardowych systemów projektowania. 

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

Optymalizacje czasu działania

Przeciążenie SideEffect z kluczem

SideEffect obsługuje teraz argumenty klucza, co pozwala wywoływać jednorazowe efekty uboczne, 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 nawet o 90% szybszy niż LaunchedEffect i o około 20% szybszy niż DisposableEffect. Pamiętaj, że SideEffect uruchamia swój efekt przed DisposableEffect i LaunchedEffect, więc zachowaj ostrożność podczas przenoszenia istniejących efektów do tego interfejsu API, zwłaszcza w przypadku LaunchedEffects, które mają być wysyłane po zakończeniu bieżącej klatki. 

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

Animacje

Interaktywne przejścia dwuetapowe

  • Nowe elementy kompozycyjneDeferredAnimatedContentDeferredAnimatedVisibility umożliwiają tworzenie atrakcyjnych przejść dwuetapowych, np. do śledzenia gestu przewidywanego przejścia wstecz.
  • Ręczne sterowanie animacją: podczas odroczonej fazy przejścia właściwości animowane (np.skala lub przesunięcie) można teraz ręcznie manipulować w czasie rzeczywistym (np. śledząc gest przesuwania).
  • Bezproblemowe przekazywanie: po zakończeniu odroczonej fazy przejścia przejmuje silnik przejścia i wykonuje bezproblemowe przekazanie, w tym transfer prędkości, do przejścia automatycznego.
  • Obsługa elementów wspólnych: nowa flaga permitTransformDuringDeferredTransitionSharedContentConfig określa, czy elementy wspólne mają się wizualnie przekształcać wraz z kontenerami nadrzędnymi podczas odroczonej fazy 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 prezentacje przypadków użycia, w których animacja sterowana gestem jest przekazywana do animacji wyzwalanej:

colorCards.gif

Integracje tekstu, danych wejściowych i platformy

Formatowanie edytowalnego tekstu

Nowe interfejsy API oferują formatowanie tekstu sformatowanego w edytowalnym tekście w BasicTextField. Możesz teraz programowo stosować i manipulować formatowaniem znaków i akapitów w tekście za pomocą SpanStyleParagraphStyle za pomocą nowej metody addStyle() w zakresie TextFieldBuffer (np. w textFieldState.edit { ... } lub InputTransformation). Dodatkowo TextFieldBuffer udostępnia interfejsy API getSpanStyles()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 do sprawdzania stanu formatowania przed edycją. Formatowanie tekstu i niestandardowe adnotacje są zachowywane po zmianach 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

Zaznaczanie tekstu

Nowy interfejs API SelectionState zapewnia zautomatyzowane sterowanie i dostrzegalność zaznaczenia tekstu w SelectionContainer. Przeniesienie obiektu SelectionState za pomocą rememberSelectionState() i przekazanie go do SelectionContainer udostępnia selectedTexts jako reaktywną listę AnnotatedStrings oraz metody takie jak selectAll()clear()select(TextRange)extendSelectionByWord().

Dodatkowo użyj getSelectableTexts(), aby pobrać wszystkie elementy tekstowe, które można zaznaczyć, w kolejności układu i zaznaczyć tekst w elementach kompozycyjnych w 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 Credential Managerem Androida (API 34+) za pomocą platformy Autofill (w przypadku API poniżej 34 obsługuje je androidx.credentials library). Dzięki dołączeniu nowej właściwości semantycznej credentialRequestCredentialRequestData, pola tekstowe mogą wyświetlać prośby o klucze dostępu, zapisane dane logowania lub logowanie bezpośrednio w procesie wprowadzania danych przez 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ń wariantów czcionek w czcionkach do pobrania.
  • Włączono automatyczne przewijanie podczas przeciągania zaznaczenia 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 element kompozycyjny SoundEffectOnInteraction, który umożliwia rezygnację. Pamiętaj, że w wyniku tej zmiany detektory kliknięć semantycznych muszą być teraz wywoływane z wątku głównego, co może wpłynąć na niewielką liczbę przypadków testowych.
  • KeyboardType zawiera teraz DateTimeDateTime, i SignedDecimal.
  • BasicSecureTextField domyślnie używa teraz TextObfuscationMode.System, a RevealLastTyped służy jako bezwzględne zastąpienie.

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 Grid. Zamiast zarządzać numerycznymi indeksami kolumn i wierszy w elementach, możesz zdefiniować regiony semantyczne w GridConfigurationScope i umieszczać elementy kompozycyjne 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 mieć pewność, że platforma pomoże Ci tworzyć piękne i wydajne aplikacje. W tej wersji skupiliśmy się na poprawie wydajności uruchamiania i widzimy teraz czas do pierwszego wyświetlenia (czas potrzebny aplikacji na wygenerowanie pierwszej klatki) porównywalny z widokami w naszych testach porównawczych.

timetoinitialdisplay@2x _v2.png

Ulepszenia testowania i narzędzi

Synchronizacja testów

Compose 1.12 wprowadza nowe interfejsy API testów, które mają na celu skrócenie czasu wykonywania testów i wyeliminowanie niestabilności podczas próbkowania stanu:

  • hasPendingWork: pasywnie sprawdza, czy interfejs użytkownika ma oczekujące zadania, bez przesuwania zegara, co jest idealne 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 API captureToImage umożliwia teraz przechwytywanie wyskakującego okienka lub okna dialogowego wraz z jego kotwicą w jednej bitmapie.
  • Dodano onRootWithViewInteraction, aby ograniczyć wyszukiwanie semantyczne Compose do określonych widoków Androida. Upraszcza to testowanie hybrydowych interfejsów użytkownika, takich jak RecyclerViews, bez konieczności używania unikalnych tagów testowych w kodzie produkcyjnym.
  • @PreviewWrapper adnotacje można teraz stosować do niestandardowych @MultiPreview klas, co umożliwia ponowne wykorzystywanie konfiguracji podglądu (np. motywów niestandardowych) w wielu komponentach.

Miłego tworzenia w Compose!

Compose 1.12 ułatwia i przyspiesza tworzenie aplikacji 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ę nią na temat tych zmian lub tego, co chcesz zobaczyć w przyszłości, w naszym systemie śledzenia problemów. Miłego tworzenia w Compose!

Scenariusz:
Czytaj dalej