חדשות על המוצר

מה חדש בגרסת אפריל 2026 של Jetpack Compose

משך הקריאה: 6 דקות
לצפייה בפרופיל של Meghan Mehta
Meghan Mehta אחראי קשרי מפתחים, Android

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

כדי להשתמש בגרסה שפורסמה היום, צריך לשדרג את גרסת Compose BOM לגרסה:

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

השינויים ב-Compose 1.11.0

הפעלה של Coroutine בבדיקות

אנחנו משיקים עדכון משמעותי לאופן שבו Compose מטפל בתזמון הבדיקות. אחרי תקופת ההצטרפות שהוכרזה ב-Compose 1.10, ממשקי ה-API לבדיקה של גרסה 2 הם עכשיו ברירת המחדל, וממשקי ה-API של גרסה 1 הוצאו משימוש. השינוי העיקרי הוא מעבר למשגר ברירת המחדל של הבדיקות. ממשקי ה-API בגרסה 1 הסתמכו על UnconfinedTestDispatcher, שהפעיל פונקציות coroutine באופן מיידי, ואילו ממשקי ה-API בגרסה 2 משתמשים ב-StandardTestDispatcher. המשמעות היא שכאשר קורוטינה מופעלת בבדיקות, היא נכנסת לתור ולא מופעלת עד שהשעון הווירטואלי מתקדם.

כך אפשר לדמות טוב יותר את תנאי הייצור, לזהות ביעילות מרוצי תהליכים ולהפוך את חבילת המקרים לבדיקה להרבה יותר חזקה ופחות לא יציבה.

כדי לוודא שהבדיקות תואמות להתנהגות הרגילה של שגרות המשך (coroutine) ולמנוע בעיות תאימות בעתיד, מומלץ מאוד להעביר את חבילת המקרים לבדיקה. כדאי לעיין במדריך המקיף להעברת נתונים (מיגרציה) כדי לקבל מידע על מיפויים של API ותיקונים נפוצים.

שיפורים ברכיבים משותפים וכלי אנימציה

הוספנו גם כמה כלים חזותיים שימושיים לניפוי באגים של רכיבים משותפים ושל Modifier.animatedBounds. עכשיו אתם יכולים לראות בדיוק מה קורה מאחורי הקלעים – כמו גבולות היעד, מסלולי האנימציה וכמה התאמות נמצאו – וכך קל יותר לזהות למה המעבר לא פועל כמו שצריך. כדי להשתמש בכלי החדש, פשוט מקיפים את SharedTransitionLayout ברכיב ה-composable‏ LookaheadAnimationVisualDebugging. 

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

אירועים במשטח המגע

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

הוספנו גם תמיכה בתנועות מורכבות יותר של משטח המגע, כפי שזוהו על ידי הפלטפורמה מאז API 34, כולל החלקות בשתי אצבעות ותנועות צביטה. התנועות האלה מזוהות באופן אוטומטי על ידי רכיבים כמו Modifier.scrollable ו-Modifier.transformable כדי לשפר את ההתנהגות עם משטחי מגע.

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

כדי לבדוק את ההתנהגות של משטח המגע, יש ממשקי API חדשים לבדיקה עם performTrackpadInput, שמאפשרים לאמת את ההתנהגות של האפליקציות כשמשתמשים בהן עם משטח מגע. אם יש לכם גלאי תנועות בהתאמה אישית, ודאו שהם פועלים כמו שצריך בכל סוגי הקלט, כולל מסכי מגע, עכברים, משטחי מגע ועטים, ושהם תומכים בגלגלי גלילה של עכברים ובתנועות במשטחי מגע.

beforeAndAfter.webp

ברירות המחדל של מארח הקומפוזיציה (זמן הריצה של Compose)

הוספנו את HostDefaultProvider,‏ LocalHostDefaultProvider,‏ HostDefaultKey ו-ViewTreeHostDefaultKey כדי לספק שירותים ברמת המארח ישירות דרך compose-runtime. כך הספריות לא צריכות להסתמך על compose-ui לחיפושים, ויש תמיכה טובה יותר ב-Kotlin Multiplatform. כדי לקשר את הערכים האלה לעץ הקומפוזיציה, מחברי הספרייה יכולים להשתמש ב-compositionLocalWithHostDefaultOf כדי ליצור CompositionLocal שפותר את ברירות המחדל מהמארח.

תצוגה מקדימה של רכיבי wrapper

תצוגות מקדימות בהתאמה אישית ב-Android Studio היא תכונה חדשה שמאפשרת להגדיר בדיוק איך התוכן של תצוגה מקדימה של פיתוח נייטיב מוצג.

הטמעה של הממשק PreviewWrapperProvider והוספה של ההערה החדשה @PreviewWrapper מאפשרות להוסיף בקלות לוגיקה מותאמת אישית, כמו החלה של Theme ספציפי. אפשר להחיל את ההערה על פונקציה שמסומנת ב-@Composable וב-@Preview או ב-@MultiPreview. כך מקבלים פתרון כללי וקל לשימוש שפועל בכל התכונות בגרסת טרום-השקה (Preview) ומצמצם באופן משמעותי את הקוד שחוזר על עצמו.

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

הוצאה משימוש והסרה

  • כפי שהודענו בפוסט בבלוג על Compose 1.10, אנחנו מוציאים משימוש את Modifier.onFirstVisible(). השם שלו גרם לעיתים קרובות לתפיסות מוטעות, במיוחד בפריסות עם טעינה מדורגת, שבהן הוא הופעל כמה פעמים במהלך הגלילה. מומלץ לעבור אל Modifier.onVisibilityChanged(), שמאפשר מעקב ידני מדויק יותר אחרי מצבי החשיפה, בהתאם לדרישות של תרחיש השימוש הספציפי שלכם.
  • הדגל ComposeFoundationFlags.isTextFieldDpadNavigationEnabled הוסר כי הניווט באמצעות כפתורי החיצים (D-pad) ב-TextFields מופעל עכשיו תמיד כברירת מחדל. ההתנהגות החדשה מבטיחה שהאירועים של כפתורי החיצים (D-pad) בשלט משחק או בשלט טלוויזיה יזיזו קודם את הסמן בכיוון הנתון. המיקוד יכול לעבור לרכיב אחר רק כשהסמן מגיע לסוף הטקסט.

ממשקי API עתידיים

בגרסה הקרובה של Compose‏ (1.12.0), ה-compileSdk ישודרג ל-compileSdk 37, עם AGP 9. כל האפליקציות והספריות שתלויות ב-Compose יירשו את הדרישה הזו. מומלץ להתעדכן בגרסאות ההפצה האחרונות, כי Compose שואף לאמץ במהירות את compileSdks החדש כדי לספק גישה לתכונות העדכניות ביותר של Android. במסמכי התיעוד שכאן מפורט מידע נוסף על גרסת ה-AGP שנתמכת ברמות API שונות. 

בגרסה 1.11.0 של Compose, ממשקי ה-API הבאים מוצגים בתור @Experimental, ונשמח לקבל מכם משוב כשתנסו אותם באפליקציות שלכם. חשוב לזכור ש@Experimental APIs מסופקים לצורך הערכה מוקדמת ומשוב, ויכול להיות שהם ישתנו באופן משמעותי או יוסרו בגרסאות עתידיות.

סגנונות (ניסיוני)

אנחנו משיקים ממשק API בסיסי ניסיוני חדש לעיצוב. Style API הוא פרדיגמה חדשה להתאמה אישית של רכיבים חזותיים, שבעבר בוצעה באמצעות משתני שינוי. הוא נועד לאפשר התאמה אישית מעמיקה וקלה יותר על ידי חשיפת קבוצה סטנדרטית של מאפיינים שניתן לעצב, עם עיצוב פשוט מבוסס-מצב ומעברים מונפשים. עם ה-API החדש הזה, אנחנו כבר רואים יתרונות מבטיחים בביצועים. אנחנו מתכננים לאמץ את Styles ברכיבי Material ברגע ש-Style API יהיה יציב.

דוגמה בסיסית לשינוי סגנון הרקע של מצב לחיצה:

@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

כדאי לעיין במסמכי התיעוד ולדווח על באגים כאן.

MediaQuery (ניסיוני)

ה-API החדש mediaQuery מספק דרך הצהרתית ויעילה להתאים את ממשק המשתמש לסביבה שלו. הוא הופך אחזור מידע מורכב לתנאים פשוטים בתוך UiMediaScope, וכך מבטיח שהקומפוזיציה מחדש תתבצע רק כשצריך.

התמיכה במגוון רחב של אותות סביבתיים – מיכולות המכשיר כמו סוגי מקלדות ודיוק הסמן, ועד למצבים תלויי הקשר כמו גודל החלון והתנוחה – מאפשרת לכם ליצור חוויות רספונסיביות מאוד. הביצועים מובנים ב-derivedMediaQuery כדי לטפל בעדכונים בתדירות גבוהה, והיכולת לשנות את היקפי ההרשאות מאפשרת לבצע בדיקות ותצוגות מקדימות בצורה חלקה בהגדרות חומרה שונות. בעבר, כדי לקבל גישה למאפיינים מסוימים של המכשיר, למשל אם המכשיר היה במצב שולחני, הייתם צריכים לכתוב הרבה קוד סטנדרטי: 

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

עכשיו, עם UIMediaQuery, אתם יכולים להוסיף את התחביר mediaQuery כדי לשלוח שאילתות לגבי מאפייני המכשיר, למשל אם המכשיר נמצא במצב שולחני:

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

כדאי לעיין במסמכי התיעוד ולדווח על באגים כאן.

רשת (ניסיוני)

‫Grid הוא API חדש ומתקדם ליצירת פריסות מורכבות ודו-ממדיות ב-Jetpack Compose. אמנם Row ו-Column מתאימים לעיצובים לינאריים, אבל Grid נותן לכם את השליטה המבנית שדרושה לארכיטקטורה ברמת המסך ולרכיבים מורכבים, בלי התקורה של רשימה שניתן לגלול בה. Grid מאפשר להגדיר את הפריסה באמצעות מסלולים, מרווחים ותאים, ומציע אפשרויות מוכרות לשינוי גודל כמו Dp, אחוזים, גודלי תוכן פנימיים ויחידות 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()
    }
}

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

Grid.gif

כדאי לעיין במסמכי התיעוד ולדווח על באגים כאן. 

FlexBox (ניסיוני)

‫FlexBox הוא קונטיינר פריסה שמיועד לממשקי משתמש רספונסיביים עם ביצועים גבוהים. הוא מנהל את גודל הפריטים ואת חלוקת השטח על סמך המידות הזמינות של המאגר.  הוא מטפל במשימות מורכבות כמו גלישה (wrap) ויישור פריטים בכמה צירים (justifyContent, alignItems, alignContent). הוא מאפשר לפריטים לגדול (grow) או להתכווץ (shrink) כדי למלא את מאגר התגים. 

@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

כדאי לעיין במסמכי התיעוד ולדווח על באגים כאן.

הטמעה חדשה של SlotTable (ניסיוני)

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

כדי לנסות את SlotTable החדש, צריך להפעיל את ComposeRuntimeFlags.isLinkBufferComposerEnabled. 

מתחילים לתכנת עוד היום!

עם כל כך הרבה ממשקי API חדשים ומלהיבים ב-Jetpack Compose, ועוד הרבה ממשקים בדרך, זה הזמן המושלם לעבור ל-Jetpack Compose.  כמו תמיד, אנחנו מעריכים את המשוב ואת הגשת בקשות להוספת תכונות (במיוחד לגבי תכונות של @Experimental שעדיין נמצאות בפיתוח) – אתם יכולים לשלוח אותם כאן. כתיבה נעימה!

כותב/ת המסמך:
להמשך קריאה