חדשות על מוצרים

מה חדש בגרסה Jetpack Compose August '26

משך הקריאה: 5 דקות
צפייה בפרופיל של Nick Butcher
Nick Butcher מנהל מוצר

היום, הגרסה של Jetpack Compose מאוגוסט 2026 יציבה! בגרסה הזו, גרסה 1.12 זמינה בכל מודולי הליבה של Compose (אפשר לעיין במיפוי המלא של BOM). נוספו ממשקי API ויזואליים עשירים כמו Mesh Gradients ותמיכה ב-Wide Color Gamut ‏ (WCG), תכונות פריסה מבניות כמו אזורים עם שמות ב-Grid, שילוב חלק עם Credential Manager של Android ושיפורים משמעותיים בבדיקות ובביצועים.

כדי לעדכן את הפרויקט לגרסה של היום, צריך לשדרג את גרסת Compose BOM לגרסה 2026.08.00:

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

שינויים שעלולים לגרום לכשלים

  • ‫AGP ו-Compile SDK: גרסה 1.12 של Compose מעדכנת את compileSdk ל-API 37, ולכן נדרשת גרסה מינימלית של AGP 9.1.2. תזכורת: Compose תמיד יכוון ל-compileSdk העדכני ביותר. כאן אפשר לקרוא מידע נוסף על השינוי הזה.
  • ‫Modifier.onFirstVisible() הוצא משימוש: כדאי לעבור אל Modifier.onVisibilityChanged(), שמאפשר מעקב מדויק יותר אחרי סף החשיפה.

גרפיקה

מפל צבעים רשתי

ב-Compose 1.12, הוספנו את MeshGradientPainter כדי לעזור לכם ליצור מעברי צבע אורגניים עם כמה נקודות.

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)
)

מידע נוסף ודוגמאות זמינים במאמרי העזרה.

תמיכה ב-HDR ובטווח רחב של צבעים

מסכים מודרניים מציעים נאמנות צבעים משופרת וטווח דינמי גבוה יותר. ב-Compose 1.12, הופעלה תמיכה מלאה בצינורות Wide Color Gamut (P3) ו-HDR rendering בגרפיקה, בצביעה וב-shaders של Compose. צבעים שמוגדרים במרחבי צבעים שאינם sRGB (כמו Display P3) נשמרים עד לרינדור בפלטפורמה ללא הגבלת צבעים. אם הצבעים משתמשים במרחב צבעים שלא נתמך (למשל CieXyz, ‏ CieLab או Oklab), אם הם מסתמכים על מרחב צבעים בגרסת Android שלא נתמכת (למשל Bt2020Hlg ב-Android מגרסה 13 ומטה), או אם האפליקציה פועלת ב-Android מגרסה 9 (API 28) ומטה, הצבעים יחזרו בבטחה ל-sRGB.

שינויים חשובים אחרים:

  • האפשרות LayerOutsets נוספה ל-GraphicsLayer ול-Modifier.graphicsLayer. אפשר להשתמש בה כדי להגדיל את הגבולות החזותיים של השכבה מעבר לגודל שנמדד. כדי למנוע את ההתנהגות המרומזת של clipToBounds כשמקדמים את השכבה למאגר מחוץ למסך, צריך להחיל LayerOutsets.

עיצובים

ב-Google I/O, הצגנו את החזון המוקדם שלנו לגבי Styles API של Compose – דרך מאוחדת ויעילה לעיצוב רכיבים. מאז, המשכנו לפתח את הארכיטקטורה הבסיסית כדי להבטיח מניעת שגיאות הקלדה ודיוק צפוי, וכדי לתמוך בפיתוח מערכות עיצוב בהתאמה אישית. 

כדי לוודא שהשכבה הבסיסית הזו תהיה נכונה, ה-API יישאר ניסיוני, ואפשר לצפות לשינויים משמעותיים. 

אופטימיזציות בזמן ריצה

Keyed SideEffect Overload

‫SideEffect תומך עכשיו בארגומנטים של מפתחות, שמאפשרים להפעיל תופעות לוואי חד-פעמיות בכל פעם שמפתחות ספציפיים משתנים. כך אפשר לשפר את הביצועים בהשוואה לשימוש ב-LaunchedEffect או ב-DisposableEffect כשלא צריך את ה-Coroutine או את בלוק ה-Dispose. SideEffect מהיר עד 90% יותר מ- LaunchedEffect ומהיר ב-20% יותר מ- DisposableEffect. הערה: האפקט של SideEffect מופעל לפני DisposableEffect ו-LaunchedEffect, לכן צריך להיזהר אם מעבירים אפקטים קיימים ל-API הזה, במיוחד עבור LaunchedEffects שמסתמכים על שליחה כדי להתחיל אחרי שהפריים הנוכחי מסתיים. 

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

אנימציה

מעברים אינטראקטיביים בשני שלבים

  • רכיבי composable חדשים: DeferredAnimatedContent ו-DeferredAnimatedVisibility מאפשרים ליצור מעברים נעימים בשני שלבים, למשל למעקב אחר תנועת החזרה החזויה.
  • שליטה ידנית באנימציה: במהלך השלב המושעה של מעבר, אפשר עכשיו לשנות מאפיינים של אנימציה (כמו קנה מידה או היסט) באופן ידני בזמן אמת (למשל, מעקב אחרי תנועת החלקה).
  • העברה חלקה: אחרי שתקופת ההשהיה מסתיימת, מנוע המעבר משתלט ומבצע העברה חלקה, כולל העברת מהירות, למעבר האוטומטי.
  • תמיכה ברכיבים משותפים: דגל permitTransformDuringDeferredTransition חדש ב-SharedContentConfig קובע אם רכיבים משותפים עוברים טרנספורמציה ויזואלית יחד עם מאגרי האב שלהם במהלך שלב המעבר המושעה.
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)
}

בהמשך מוצגות שתי הדגמות של תרחישי שימוש שבהם אנימציה מבוססת-מחוות מועברת לאנימציה מופעלת:

colorCards.gif

שילובים של טקסט, קלט ופלטפורמות

עיצוב טקסט שניתן לערוך

ממשקי API חדשים מציעים עיצוב טקסט עשיר לטקסט שניתן לעריכה ב-BasicTextField. עכשיו אפשר להחיל ולשנות עיצוב של תווים ופסקאות בתוך השורה באופן פרוגרמטי באמצעות SpanStyle ו- ParagraphStyle דרך השיטה החדשה addStyle() בתוך היקף TextFieldBuffer (למשל בתוך textFieldState.edit { ... } או InputTransformation). בנוסף, TextFieldBuffer מספקת ממשקי API של getSpanStyles() ו- getParagraphStyles() שמחזירים אובייקטים של TrackedRange, וכך מאפשרים לקרוא, לעדכן או להסיר סגנונות שהוחלו. בנוסף ליצירת עיצוב, TextFieldState חושף עכשיו מאפיין textStyles לקריאה בלבד כדי לשאול על סגנונות פעילים בטווחים, ו- TextFieldBuffer מספק originalTextStyles כדי לבדוק את מצב העיצוב לפני עריכה. עיצוב הטקסט וההערות המותאמות אישית נשמרים גם אחרי שינויים בהגדרות.

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

בחירת טקסט

‫API חדש של SelectionState מספק שליטה פרוגרמטית ויכולת צפייה בבחירת טקסט בתוך SelectionContainer. העלאה של אובייקט SelectionState באמצעות rememberSelectionState() והעברה אל SelectionContainer חושפת את selectedTexts כרשימה ריאקטיבית של AnnotatedStrings ומספקת שיטות כמו selectAll(),‏ clear(),‏ select(TextRange) ו-extendSelectionByWord().

בנוסף, אפשר להשתמש ב-getSelectableTexts() כדי לאחזר את כל פריטי הטקסט שאפשר לבחור לפי סדר הפריסה, ולבחור טקסט ברכיבים הניתנים להרכבה ב-SelectionContainer באמצעות טווח גלובלי. 

@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.")
        }
    }
}

Credential Manager Integration

שדות הטקסט להזנת נתונים משולבים עכשיו באופן מובנה עם Credential Manager ב-Android (API 34 ומעלה) באמצעות מסגרת המילוי האוטומטי (בגרסאות API מתחת ל-34, הטיפול מתבצע באמצעות androidx.credentials library). על ידי צירוף מאפיין הסמנטיקה החדש credentialRequest עם CredentialRequestData, שדות הטקסט להזנת נתונים יכולים להציג בקשות למפתחות גישה, לפרטי כניסה שמורים או לכניסה ישירות בתהליך הזנת נתוני המשתמש.

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

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

שינויים חשובים אחרים:

  • תמיכה בהגדרות של וריאציות גופנים בגופנים שאפשר להוריד.
  • הפעלנו גלילה אוטומטית כשגוררים בחירת טקסט מעבר לאזור התצוגה ב-SelectionContainer.
  • נוספה תמיכה בצלילי אינטראקציה אוטומטיים (קליקים וניווט במיקוד) לרכיבי Compose, עם קומפוזיציה חדשה SoundEffectOnInteraction שמאפשרת ביטול הסכמה. שימו לב: כתוצאה מהשינוי הזה, עכשיו צריך להפעיל את מאזיני הקליקים הסמנטיים מה-thread הראשי, וזה עשוי להשפיע על מספר קטן של תרחישי בדיקה.
  • ‫KeyboardType כולל עכשיו את Date, Time, DateTime ו-SignedDecimal.
  • BasicSecureTextField משתמש עכשיו ב-TextObfuscationMode.System כברירת מחדל, ואילו RevealLastTyped משמש כשינוי מוחלט.

שיפורים בפריסה

אזורים עם שמות בפריסת משבצות

עכשיו קל יותר ליצור פריסות מורכבות של דו-ממד באמצעות אזורים עם שמות ברכיב @Experimental Grid. במקום לנהל אינדקסים מספריים של עמודות ושורות בין פריטים, אפשר להגדיר אזורים סמנטיים ב-GridConfigurationScope ולמקם רכיבים שניתנים להרכבה לפי שם האזור.

@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"))
    }
}

מידע נוסף מופיע במאמרי העזרה.

ביצועים

כמו בכל גרסה, אנחנו ממשיכים להשקיע בביצועים של Compose כדי לוודא שהמסגרת עוזרת לכם ליצור אפליקציות יפות עם ביצועים טובים. בגרסה הזו התמקדנו בשיפור הביצועים של ההפעלה, ועכשיו אנחנו רואים את הזמן עד להצגה הראשונית (הזמן שנדרש לאפליקציה כדי ליצור את הפריימים הראשונים שלה) שדומה לנתוני הצפיות בהשוואות הביצועים שלנו.

timetoinitialdisplay@2x _v2.png

שדרוגים של בדיקות וכלים

בדיקת הסנכרון

ב-Compose 1.12 מוצגים ממשקי API חדשים לבדיקות, שנועדו לקצר את זמני ביצוע הבדיקות ולמנוע תנודות במהלך דגימת ערך דינמי:

  • ‫hasPendingWork: בודקת באופן פסיבי אם יש עבודה בהמתנה בממשק המשתמש בלי להריץ את השעון, וזה אידיאלי ללולאות אנימציה ידניות.
  • ‫runWithoutImplicitWait: משבית באופן זמני סנכרון מרומז כשמבצעים מעבר בין מסגרות של שעון ידני (למשל, בדיקות של אנימציה).
@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)
            }
        }
    }
}

שינויים חשובים אחרים:

  • ה-API captureToImage מאפשר עכשיו לצלם חלון קופץ או תיבת דו-שיח יחד עם רכיב העוגן שלהם במפת סיביות אחת.
  • נוספה onRootWithViewInteraction כדי להגדיר את היקף החיפושים הסמנטיים של Compose לתצוגות ספציפיות של Android. כך אפשר לפשט את הבדיקה של ממשקי משתמש היברידיים, כמו RecyclerViews, בלי שיהיה צורך בתגי בדיקה ייחודיים בקוד הייצור.
  • עכשיו אפשר להחיל הערות @PreviewWrapper על מחלקות מותאמות אישית של @MultiPreview, וכך להשתמש שוב בהגדרות של תצוגה מקדימה (כמו ערכות נושא מותאמות אישית) בכמה רכיבים.

כתיבה מהנה!

‫Compose 1.12 הופך את פיתוח האפליקציות לקל וליצירתי יותר מאי פעם, עם מעברי צבע רשתיים, תמיכה במגוון רחב של צבעים, גופנים משתנים שניתנים להורדה, שילוב של Credential Manager וכלים מהירים יותר לבדיקה. כמו תמיד, אנחנו מעריכים את המשוב שלכם, ולכן אתם מוזמנים לשתף אותנו בדעות שלכם על השינויים האלה או על מה שהייתם רוצים לראות בהמשך בכלי למעקב אחר בעיות. כתיבה נעימה!

נכתב על ידי:
להמשך קריאה