اخبار محصول

ویژگی‌های جدید Jetpack Compose نسخه دسامبر 25

مطالعه ۶ دقیقه‌ای
Nick Butcher
مدیر محصول

امروز، نسخه Jetpack Compose دسامبر 2025 پایدار است. این نسخه شامل نسخه 1.10 از ماژول‌های اصلی Compose و نسخه 1.4 از Material 3 (به نگاشت کامل BOM مراجعه کنید) است که ویژگی‌های جدید و بهبودهای عمده‌ای در عملکرد را اضافه می‌کند.

برای استفاده از نسخه امروز، نسخه Compose BOM خود را به 2025.12.00 ارتقا دهید:

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

بهبود عملکرد

ما می‌دانیم که عملکرد زمان اجرای برنامه شما برای شما و کاربرانتان بسیار مهم است، بنابراین عملکرد اولویت اصلی تیم Compose بوده است. این نسخه بهبودهای متعددی را به همراه دارد - و شما می‌توانید همه آنها را تنها با ارتقا به آخرین نسخه دریافت کنید. معیارهای پیمایش داخلی ما نشان می‌دهد که Compose اکنون با عملکردی که در صورت استفاده از Views مشاهده می‌کنید، مطابقت دارد:

janky.png

معیار عملکرد پیمایش (Scroll Performance benchmark) برای مقایسه‌ی Views و Jetpack Compose در نسخه‌های مختلف Compose

ترکیب قابل مکث در پیش واکشی تنبل

ترکیب قابل مکث در پیش‌واکشی تنبل اکنون به طور پیش‌فرض فعال است. این یک تغییر اساسی در نحوه عملکرد زمان‌بندی‌های زمان اجرای Compose است که برای کاهش قابل توجه jank در حین حجم کاری سنگین رابط کاربری طراحی شده است.

پیش از این، به محض شروع یک ترکیب، باید تا زمان تکمیل اجرا می‌شد. اگر یک ترکیب پیچیده بود، این می‌توانست نخ اصلی را برای مدت طولانی‌تری از یک فریم مسدود کند و باعث شود رابط کاربری متوقف شود. با ترکیب قابل مکث، اکنون زمان اجرا می‌تواند در صورت اتمام زمان، کار خود را "متوقف" کند و کار را در فریم بعدی از سر بگیرد. این امر به ویژه هنگامی که با پیش واکشی طرح‌بندی تنبل برای آماده‌سازی فریم‌ها از قبل استفاده می‌شود، مؤثر است. APIهای CacheWindow طرح‌بندی تنبل که در Compose 1.9 معرفی شدند، راهی عالی برای پیش واکشی محتوای بیشتر و بهره‌مندی از ترکیب قابل مکث برای ایجاد عملکرد رابط کاربری بسیار روان‌تر هستند.

قابل مکث.gif

ترکیب قابل مکث همراه با پیش واکشی تنبل به کاهش خطاهای ناخواسته کمک می‌کند

ما همچنین عملکرد را در جاهای دیگر، با بهبودهایی در Modifier.onPlaced ، Modifier.onVisibilityChanged و سایر پیاده‌سازی‌های اصلاح‌کننده، بهینه کرده‌ایم. ما به سرمایه‌گذاری در بهبود عملکرد Compose ادامه خواهیم داد.

ویژگی‌های جدید

حفظ

Compose تعدادی API برای نگهداری و مدیریت وضعیت در چرخه‌های عمر مختلف ارائه می‌دهد؛ برای مثال، remember وضعیت را در سراسر ترکیب‌ها حفظ می‌کند، و rememberSavable / rememberSerializable برای حفظ وضعیت در طول فعالیت یا بازآفرینی فرآیند. retain یک API جدید است که بین این APIها قرار می‌گیرد و شما را قادر می‌سازد مقادیر را در طول تغییرات پیکربندی بدون سریالی شدن حفظ کنید، اما نه در طول مرگ فرآیند. از آنجایی که retain وضعیت شما را سریالی نمی‌کند، می‌توانید اشیاء مانند عبارات لامبدا، جریان‌ها و اشیاء بزرگ مانند بیت‌مپ‌ها را که به راحتی سریالی نمی‌شوند، حفظ کنید. به عنوان مثال، می‌توانید retain برای مدیریت یک پخش‌کننده رسانه (مانند ExoPlayer) استفاده کنید تا مطمئن شوید که پخش رسانه با تغییر پیکربندی قطع نمی‌شود.

  @Composable

fun MediaPlayer() {

    val applicationContext = LocalContext.current.applicationContext

    val exoPlayer = retain { ExoPlayer.Builder(applicationContext).apply { ... }.build() }

    ...

}

ما می‌خواهیم از جامعه توسعه‌دهندگان اندروید (به‌ویژه تیم Circuit ) که در طراحی این ویژگی تأثیرگذار بوده‌اند و به آن کمک کرده‌اند، تشکر کنیم.

ماده ۱.۴

نسخه ۱.۴.۰ کتابخانه material3 تعدادی کامپوننت و بهبود جدید اضافه کرده است:

  • TextField اکنون یک نسخه آزمایشی مبتنی بر TextFieldState ارائه می‌دهد که روشی قوی‌تر برای مدیریت وضعیت متن ارائه می‌دهد. علاوه بر این، انواع جدید SecureTextField و OutlinedSecureTextField اکنون ارائه شده‌اند. قابلیت ترکیب Text متریال اکنون از رفتار autoSize پشتیبانی می‌کند.
  • کامپوننت carousel اکنون یک نوع جدید HorizontalCenteredHeroCarousel ارائه می‌دهد.
  • TimePicker اکنون از جابجایی بین حالت‌های انتخابگر و ورودی پشتیبانی می‌کند.
  • یک دسته‌ی عمودی برای کشیدن و رها کردن به کاربران کمک می‌کند تا اندازه و/یا موقعیت یک پنجره‌ی تطبیقی ​​را تغییر دهند.
قهرمان-چرخ فلک-محور.webp

چرخ فلک قهرمان افقی متمرکز

توجه داشته باشید که APIهای Expressive متریال ۳ همچنان در نسخه‌های آلفای کتابخانه material3 در حال توسعه هستند. برای کسب اطلاعات بیشتر، به این سخنرانی اخیر مراجعه کنید:

ویژگی‌های جدید انیمیشن

ما همچنان در حال گسترش APIهای انیمیشن خود هستیم، از جمله به‌روزرسانی‌هایی برای سفارشی‌سازی انیمیشن‌های عناصر مشترک.

عناصر اشتراکی پویا

به طور پیش‌فرض، انیمیشن‌های sharedElement() و sharedBounds() سعی در متحرک‌سازی دارند.

طرح‌بندی هر زمان که یک کلید منطبق در حالت هدف پیدا شود، تغییر می‌کند. با این حال، ممکن است بخواهید این انیمیشن را به صورت پویا بر اساس شرایط خاص، مانند جهت پیمایش یا حالت فعلی رابط کاربری، غیرفعال کنید.

برای کنترل اینکه آیا انتقال عنصر مشترک رخ می‌دهد یا خیر، اکنون می‌توانید SharedContentConfig ارسال شده به rememberSharedContentState() را سفارشی کنید. ویژگی isEnabled تعیین می‌کند که آیا عنصر مشترک فعال است یا خیر.

  SharedTransitionLayout {

        val transition = updateTransition(currentState)

        transition.AnimatedContent { targetState ->

            // Create the configuration that depends on state changing.

            fun animationConfig() : SharedTransitionScope.SharedContentConfig {

                return object : SharedTransitionScope.SharedContentConfig {

                    override val SharedTransitionScope.SharedContentState.isEnabled: Boolean

                        get() =

                            // determine whether to perform a shared element transition

                }

            }

}

برای اطلاعات بیشتر به مستندات مراجعه کنید.

تابع ()skipToLookaheadPosition برای تغییر موقعیت (modifier.skipToLookaheadPosition)

یک اصلاح‌کننده جدید، Modifier.skipToLookaheadPosition() ، در این نسخه اضافه شده است که موقعیت نهایی یک composable را هنگام اجرای انیمیشن‌های عنصر مشترک حفظ می‌کند. این امکان اجرای انتقال‌هایی مانند انیمیشن نوع "آشکارسازی" را فراهم می‌کند، همانطور که در نمونه Androidify با آشکارسازی تدریجی دوربین مشاهده می‌شود. برای اطلاعات بیشتر به نکته ویدیویی اینجا مراجعه کنید:

سرعت اولیه در انتقال عناصر مشترک

این نسخه یک API جدید برای انتقال عنصر مشترک به نام prepareTransitionWithInitialVelocity اضافه می‌کند که به شما امکان می‌دهد یک سرعت اولیه (مثلاً از یک ژست) را به یک انتقال عنصر مشترک ارسال کنید:

  Modifier.fillMaxSize()

    .draggable2D(

        rememberDraggable2DState { offset += it },

        onDragStopped = { velocity ->

            // Set up the initial velocity for the upcoming shared element

            // transition.

            sharedContentStateForDraggableCat

                ?.prepareTransitionWithInitialVelocity(velocity)

            showDetails = false

        },

    )
اشتراک‌گذاری.gif

یک گذار عنصر مشترک که با سرعت اولیه از یک ژست شروع می‌شود

انتقال‌های پنهان

EnterTransition و ExitTransition نحوه ظاهر شدن یا ناپدید شدن یک ترکیب AnimatedVisibility / AnimatedContent را تعریف می‌کنند. یک گزینه آزمایشی جدید برای پوشش دادن یا پوشاندن محتوا به شما امکان می‌دهد رنگی را برای پوشش یا پوشاندن محتوا مشخص کنید؛ به عنوان مثال، محو کردن/بیرون دادن یک لایه سیاه نیمه مات روی محتوا:

حجاب_2.gif

محتوای انیمیشنی پوشیده - به پوشش نیمه‌شفاف (یا استریمر) روی محتوای شبکه‌ای در طول انیمیشن توجه کنید.

  AnimatedContent(

    targetState = page,

    modifier = Modifier.fillMaxSize().weight(1f),

    transitionSpec = {

        if (targetState > initialState) {

            (slideInHorizontally { it } togetherWith

                    slideOutHorizontally { -it / 2 } + veilOut(targetColor = veilColor))

        } else {

            slideInHorizontally { -it / 2 } +

                    unveilIn(initialColor = veilColor) togetherWith slideOutHorizontally { it }

        }

    },

) { targetPage ->

    ...

}

تغییرات آینده

منسوخ شدن Modifier.onFirstVisible

در Compose 1.9 Modifier.onVisibilityChanged و Modifier.onFirstVisible معرفی شدند. پس از بررسی بازخورد شما، مشخص شد که قرارداد Modifier.onFirstVisible به طور قطعی قابل اجرا نیست؛ به طور خاص، هنگامی که یک آیتم برای اولین بار قابل مشاهده می‌شود. به عنوان مثال، یک طرح‌بندی تنبل ممکن است آیتم‌هایی را که از viewport خارج می‌شوند، دور بریزد و اگر دوباره به view اسکرول شوند، دوباره آنها را ترکیب کند. در این شرایط، فراخوانی onFirstVisible دوباره اجرا می‌شود، زیرا یک آیتم تازه ترکیب شده است. رفتار مشابهی نیز هنگام بازگشت به صفحه‌ای که قبلاً بازدید شده و حاوی onFirstVisible است، رخ می‌دهد. به همین ترتیب، ما تصمیم گرفته‌ایم که این اصلاح‌کننده را در نسخه بعدی Compose (1.11) منسوخ کنیم و توصیه می‌کنیم به onVisibilityChanged مهاجرت کنید. برای اطلاعات بیشتر به مستندات مراجعه کنید.

اعزام کوروتین در تست‌ها

ما قصد داریم ارسال کوروتین را در تست‌ها تغییر دهیم تا تست‌های بدون وقفه (Test Dispatcher) بهبود یابند و مشکلات بیشتری شناسایی شوند. در حال حاضر، تست‌ها از UnconfinedTestDispatcher استفاده می‌کنند که با رفتار محیط عملیاتی متفاوت است؛ به عنوان مثال، ممکن است افکت‌ها به جای اینکه در صف قرار گیرند، بلافاصله اجرا شوند. در نسخه آینده، قصد داریم یک API جدید معرفی کنیم که به طور پیش‌فرض از StandardTestDispatcher برای مطابقت با رفتارهای محیط عملیاتی استفاده می‌کند. می‌توانید این رفتار جدید را اکنون در نسخه ۱.۱۰ امتحان کنید:

  @get:Rule // also createAndroidComposeRule, createEmptyComposeRule

val rule = createComposeRule(effectContext = StandardTestDispatcher())

استفاده از StandardTestDispatcher وظایف را در صف قرار می‌دهد، بنابراین باید از مکانیسم‌های همگام‌سازی مانند composeTestRule.waitForIdle() یا composeTestRule.runOnIdle() استفاده کنید. اگر تست شما runTest استفاده می‌کند، باید مطمئن شوید که runTest و قانون Compose شما برای همگام‌سازی، نمونه StandardTestDispatcher یکسانی را به اشتراک می‌گذارند.

  // 1. Create a SINGLE dispatcher instance

val testDispatcher = StandardTestDispatcher()



// 2. Pass it to your Compose rule

@get:Rule

val composeRule = createComposeRule(effectContext = testDispatcher)



@Test

// 3. Pass the *SAME INSTANCE* to runTest

fun myTest() = runTest(testDispatcher) {

    composeRule.setContent { /* ... */ }

}

ابزارها

API های عالی شایسته ابزارهای عالی هستند و اندروید استودیو اخیراً تعدادی افزونه برای توسعه دهندگان Compose ارائه داده است:

برای دیدن این ابزارها در عمل، این نمایش اخیر را تماشا کنید:

آهنگسازی شاد

ما همچنان به سرمایه‌گذاری روی Jetpack Compose ادامه می‌دهیم تا APIها و ابزارهایی را که برای ایجاد رابط‌های کاربری زیبا و غنی نیاز دارید، در اختیارتان قرار دهیم. ما برای نظرات شما ارزش قائلیم، بنابراین لطفاً نظرات خود را در مورد این تغییرات یا آنچه که مایلید در مرحله بعدی در ردیاب مشکلات ما ببینید، به اشتراک بگذارید.

    نوشته شده توسط:

    ادامه مطلب