أخبار المنتجات

الميزات الجديدة في إصدار ديسمبر 2025 من Jetpack Compose

مدّة القراءة: 6 دقائق
عرض الملف الشخصي لـ Nick Butcher
Nick Butcher مدير منتجات

أصبح إصدار ديسمبر 2025 من Jetpack Compose مستقرًا اليوم. يحتوي هذا الإصدار على الإصدار 1.10 من وحدات Compose الأساسية والإصدار 1.4 من Material 3 (اطّلِع على عملية الربط الكاملة بين قائمة إدارة المواد BOM)، ما يضيف ميزات جديدة ويُحسِّن الأداء بشكل كبير.

لاستخدام إصدار اليوم، عليك ترقية إصدار قائمة إدارة المواد في Compose إلى 2025.12.00:

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

تحسينات الأداء

ندرك أنّ أداء وقت تشغيل تطبيقك مهم جدًا لك وللمستخدمين، لذا كان الأداء من أهم أولويات فريق Compose. يتضمّن هذا الإصدار عددًا من التحسينات، ويمكنك الحصول عليها جميعًا من خلال الترقية إلى أحدث إصدار فقط. توضّح المقاييس الداخلية التي أجريناها على التمرير أنّ أداء Compose يطابق الآن الأداء الذي كنت ستحصل عليه إذا استخدمت طريقة العرض:

janky.png

مقياس أداء التمرير الذي يقارن بين طريقة العرض وJetpack Compose في إصدارات مختلفة من Compose

الإنشاء القابل للإيقاف المؤقت في ميزة "التحميل المسبق الكسول"

تم تفعيل ميزة الإنشاء القابل للإيقاف المؤقت في ميزة الجلب المسبق الكسول تلقائيًا. وهذا تغيير أساسي في طريقة جدولة وقت تشغيل Compose للأعمال، وهو مصمّم للحدّ بشكل كبير من إيقاف مؤقت لعرض واجهة المستخدم أثناء أحمال عمل واجهة المستخدم الكبيرة.

في السابق، كان يجب إكمال أي عملية إنشاء بعد بدئها. إذا كانت عملية الإنشاء معقّدة، قد يؤدي ذلك إلى حظر سلسلة التعليمات الرئيسية لفترة أطول من إطار واحد، ما يؤدي إلى تجميد واجهة المستخدم. باستخدام ميزة "الإنشاء القابل للإيقاف المؤقت"، يمكن لوقت التشغيل الآن "إيقاف" عمله مؤقتًا إذا كان الوقت ينفد واستئناف العمل في الإطار التالي. يكون هذا الإجراء فعالاً بشكل خاص عند استخدامه مع ميزة "التحميل المسبق للتنسيق الكسول" لإعداد الإطارات مسبقًا. تُعدّ واجهات برمجة التطبيقات Lazy layout CacheWindow التي تم طرحها في Compose 1.9 طريقة رائعة لإجراء جلب مسبق لمزيد من المحتوى والاستفادة من ميزة "الإنشاء القابل للإيقاف المؤقت" لإنتاج أداء أكثر سلاسة لواجهة المستخدم.

pausable.gif

تساعد ميزة "التكوين القابل للإيقاف المؤقت" مع ميزة "الجلب المسبق الكسول" في الحدّ من إيقاف مؤقت لعرض واجهة المستخدم

لقد حسّنّا أيضًا الأداء في أماكن أخرى، من خلال إجراء تحسينات على Modifier.onPlaced وModifier.onVisibilityChanged وعمليات تنفيذ المعدِّلات الأخرى. سنواصل الاستثمار في تحسين أداء Compose.

الميزات الجديدة

الاحتفاظ

تقدّم Compose عددًا من واجهات برمجة التطبيقات للاحتفاظ بالحالة وإدارتها خلال دورات حياة مختلفة، مثلاً، remember تحتفظ بالحالة خلال عمليات الإنشاء، وrememberSavable/rememberSerializable للاحتفاظ بالحالة خلال إعادة إنشاء النشاط أو العملية.retain هي واجهة برمجة تطبيقات جديدة تقع بين واجهات برمجة التطبيقات هذه، ما يتيح لك الاحتفاظ بالقيم خلال تغييرات الإعدادات بدون تسلسلها، ولكن ليس خلال إيقاف العملية نهائيًا. بما أنّ الدالة retain لا تسلسل حالتك، يمكنك الاحتفاظ بعناصر مثل تعابير لامدا والتدفقات والعناصر الكبيرة مثل الصور النقطية التي لا يمكن تسلسلها بسهولة. على سبيل المثال، يمكنك استخدام الدالة retain لإدارة مشغّل وسائط (مثل ExoPlayer) لضمان عدم انقطاع تشغيل الوسائط بسبب تغيير الإعدادات.

@Composable

fun MediaPlayer() {

    val applicationContext = LocalContext.current.applicationContext

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

    ...

}

نريد أن نقدّم شكرنا لمجتمع AndroidDev (خاصةً فريق Circuit) الذي أثّر في تصميم هذه الميزة وساهم فيه.

Material 1.4

يضيف الإصدار 1.4.0 من مكتبة material3 عددًا من المكوّنات والتحسينات الجديدة:

  • TextField يقدّم الآن إصدارًا تجريبيًا يستند إلى TextFieldState، ما يوفّر طريقة أكثر فعالية لإدارة حالة النص. بالإضافة إلى ذلك، يتم الآن تقديم متغيرات جديدة من SecureTextField و OutlinedSecureTextField. تتوافق الدالة Text القابلة للإنشاء في Material الآن مع سلوك autoSize.
  • يقدّم مكوّن شريط الصور الدوّار الآن متغيرًا جديدًا هو HorizontalCenteredHeroCarousel variant.
  • TimePicker تتيح الآن التبديل بين وضعَي أداة الاختيار والإدخال.
  • يساعد مقبض السحب العمودي المستخدمين في تغيير حجم و/أو موضع لوحة تكيفية.
centered-hero-carousel.webp

شريط الصور الدوّار الأفقي في المنتصف

يُرجى العِلم أنّه لا يزال يتم تطوير واجهات برمجة التطبيقات Material 3 Expressive في الإصدارات التجريبية من مكتبة material3. لمزيد من المعلومات، يمكنك الاطّلاع على هذا الحديث الأخير:

ميزات الرسوم المتحركة الجديدة

نواصل توسيع نطاق واجهات برمجة التطبيقات للرسوم المتحركة، بما في ذلك التعديلات لتخصيص الرسوم المتحركة للعناصر المشترَكة.

العناصر المشترَكة الديناميكية

تحاول الرسوم المتحركة 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

                }

            }

}

يمكنك الاطّلاع على المستندات لمزيد من المعلومات.

‫Modifier.skipToLookaheadPosition()

تمت إضافة معدِّل جديد، هو Modifier.skipToLookaheadPosition()، في هذا الإصدار، ويحتفظ هذا المعدِّل بالموضع النهائي لعنصر قابل للإنشاء عند تنفيذ الرسوم المتحركة للعناصر المشترَكة. يسمح ذلك بتنفيذ عمليات انتقال مثل الرسوم المتحركة من نوع "الكشف"، كما هو موضّح في نموذج Androidify مع الكشف التدريجي عن الكاميرا. يمكنك الاطّلاع على نصيحة الفيديو هنا لمزيد من المعلومات: 

السرعة الأولية في عمليات انتقال العناصر المشترَكة

يضيف هذا الإصدار واجهة برمجة تطبيقات جديدة لعمليات انتقال العناصر المشترَكة، هي 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

        },

    )
fling-shared.gif

عملية انتقال عنصر مشترَك تبدأ بسرعة أولية من إيماءة

عمليات الانتقال المحجوبة

EnterTransition وExitTransition تحدّدان كيفية ظهور أو اختفاء دالة مركّبة من AnimatedVisibility/AnimatedContent. يتيح لك خيار الحجاب التجريبي الجديد تحديد لون لحجب المحتوى أو إخفائه، مثلاً، عرض طبقة سوداء شبه شفافة تدريجيًا فوق المحتوى أو إخفاؤها تدريجيًا:

veil_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 نهائيًا

طرح الإصدار 1.9 من Compose Modifier.onVisibilityChanged وModifier.onFirstVisible. بعد مراجعة ملاحظاتك، تبيّن أنّه لا يمكن الالتزام بشكل حتمي بعقد Modifier.onFirstVisible، وتحديدًا عندما يصبح العنصر مرئيًا لأول مرة. على سبيل المثال، قد يتخلّص التنسيق الكسول من العناصر التي يتم تمريرها خارج إطار العرض، ثم يعيد إنشاءها إذا تم تمريرها مرة أخرى إلى إطار العرض. في هذه الحالة، سيتم تشغيل معاودة الاتصال onFirstVisible مرة أخرى، لأنّه عنصر تم إنشاؤه حديثًا. سيحدث سلوك مماثل أيضًا عند التنقّل مرة أخرى إلى شاشة تم عرضها سابقًا وتحتوي على onFirstVisible. على هذا النحو، قرّرنا إيقاف هذا المعدِّل نهائيًا في الإصدار التالي من Compose (1.11) وننصحك بنقل البيانات إلى onVisibilityChanged. يمكنك الاطّلاع على المستندات لمزيد من المعلومات.

إرسال كوروتين في الاختبارات

نخطّط لتغيير توزيع مهام الكوروتين في الاختبارات لتحسين عدم استقرار الاختبارات ورصد المزيد من المشاكل. تستخدم الاختبارات حاليًا UnconfinedTestDispatcher، الذي يختلف عن سلوك الإنتاج، مثلاً، قد يتم تشغيل التأثيرات على الفور بدلاً من وضعها في قائمة الانتظار. في إصدار مستقبلي، نخطّط لطرح واجهة برمجة تطبيقات جديدة تستخدم StandardTestDispatcher تلقائيًا لمطابقة سلوكيات الإنتاج. يمكنك تجربة السلوك الجديد الآن في الإصدار 1.10:

@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 { /* ... */ }

}

الأدوات

تستحق واجهات برمجة التطبيقات الرائعة أدوات رائعة، ويتضمّن استوديو Android عددًا من الإضافات الأخيرة لمطوّري Compose:

لرؤية هذه الأدوات قيد التنفيذ، يمكنك مشاهدة هذا العرض التوضيحي الأخير:

نتمنى لك تجربة إنشاء ممتعة

نواصل الاستثمار في Jetpack Compose لتزويدك بواجهات برمجة التطبيقات والأدوات التي تحتاج إليها لإنشاء واجهات مستخدم جميلة وغنية. نقدّر ملاحظاتك، لذا يُرجى مشاركة ملاحظاتك حول هذه التغييرات أو ما تريد رؤيته بعد ذلك في أداة تتبُّع المشاكل.

من تأليف:
متابعة القراءة