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.
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
GraphicsLayeriModifier.graphicsLayerdodanoLayerOutsets, którego możesz użyć, aby zwiększyć wizualne granice warstwy poza jej zmierzony rozmiar. ZastosujLayerOutsets, aby uniknąć domyślnego zachowaniaclipToBounds, 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
DeferredTargetAnimationnie jest już w fazie eksperymentalnej.
Interaktywne przejścia dwuetapowe
- Nowe funkcje kompozycyjne:
DeferredAnimatedContentiDeferredAnimatedVisibilityumoż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
permitTransformDuringDeferredTransitionwSharedContentConfigokreś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:
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. KeyboardTypeobejmuje terazDate,Time,DateTimeiSignedDecimal.BasicSecureTextFielddomyślnie używa terazTextObfuscationMode.System, aRevealLastTypedjest 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.
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
captureToImageAPI 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
@PreviewWrappermoż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!
-
Wiadomości o usługachGooglebook to nowa kategoria laptopów opartych na wspólnej platformie Androida. Wydajne urządzenia od partnerów takich jak HP, Dell, Lenovo, Acer i Asus łączą wygodę urządzeń mobilnych z mocą komputerów stacjonarnych.
Fahd Imtiaz, Loryn Hairston • Czas czytania: 4 min -
Wiadomości o usługachWraz z wprowadzeniem Pixela 11 Pro Fold, zegarka Pixel Watch 5 i całej rodziny Pixel użytkownicy mogą płynnie przechodzić między różnymi rozmiarami ekranów, unikalnymi pozycjami i inteligentnymi funkcjami.
-
Wiadomości o usługachDziś oficjalnie obchodzimy 5 rocznicę premiery Jetpack Compose 1.0. Od wersji 1.0, którą ogłosiliśmy 28 lipca 2021 r., do najnowszej wersji 1.11 interfejsy API znacznie się rozwinęły. Chcemy to uczcić.
Rebecca Franks, Nick Butcher, Loryn Hairston • Czas czytania: 4 minuty
Otrzymuj co tydzień najnowsze informacje o tworzeniu aplikacji na Androida na swoją skrzynkę odbiorczą.