Material 3 Expressive هو التطوّر التالي في التصميم المتعدد الأبعاد. ويشمل ذلك ميزات محدَّثة خاصة بالمظاهر والمكوّنات والتخصيص، مثل الألوان الديناميكية.
يركّز هذا الدليل على نقل التطبيقات من مكتبة Wear Compose Material 2.5 (androidx.wear.compose) Jetpack إلى مكتبة Wear Compose Material 3 (androidx.wear.compose.material3) Jetpack.
الأساليب
لنقل رمز تطبيقك من M2.5 إلى M3، اتّبِع الأسلوب نفسه الموضّح في دليل نقل Compose Material، وخاصةً:
- يجب عدم استخدام كل من M2.5 وM3 في تطبيق واحد على المدى الطويل.
- يجب التوقّف عن استخدام مكتبات Horologist Composables أو Compose Layout أو Compose Material. بدلاً من ذلك، استخدِم المكوّنات في M3.
- اتّبِع نهجًا تدريجيًا.
الطلبات التابعة
تتضمّن حزمة M3 إصدارًا مختلفًا عن M2.5:
M2.5
implementation("androidx.wear.compose:compose-material:1.4.0")
التصميم 3
implementation("androidx.wear.compose:compose-material3:1.7.0")
يمكنك الاطّلاع على أحدث إصدارات M3 في صفحة إصدارات Wear Compose.
قدّم الإصدار 1.7.0 من مكتبة Wear Compose Foundation بعض المكوّنات الجديدة المصمّمة للعمل مع مكوّنات Material 3.
وبالمثل، يتضمّن SwipeDismissableNavHost من مكتبة Wear Compose Navigation رسمًا متحركًا معدَّلاً عند تشغيله على الإصدار 6 من نظام التشغيل Wear OS (المستوى 36 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث. عند التحديث إلى إصدار Material 3 من Wear Compose، ننصحك أيضًا بتحديث مكتبتَي Wear Compose Foundation وNavigation:
implementation("androidx.wear.compose:compose-foundation:1.7.0")
implementation("androidx.wear.compose:compose-navigation:1.7.0")
المظهر
في كلّ من M2.5 وM3، يُطلق على الدالة المركّبة الخاصة بالمظهر الاسم MaterialTheme، ولكن تختلف حِزم الاستيراد والمَعلمات. في الإصدار M3، تم تغيير اسم المَعلمة Colors إلى ColorScheme، وتم تقديم MotionScheme لتنفيذ عمليات الانتقال.
M2.5
import androidx.wear.compose.material.MaterialTheme
MaterialTheme(
colors = AppColors,
typography = AppTypography,
shapes = AppShapes,
content = content
)
التصميم 3
import androidx.wear.compose.material3.MaterialTheme // ... MaterialTheme( colorScheme = ColorScheme(), typography = Typography(), shapes = Shapes(), motionScheme = MotionScheme.standard(), content = { /*content here*/ } )
اللون
يختلف نظام الألوان في M3 بشكل كبير عن M2.5. ازداد عدد مَعلمات الألوان، وأصبحت لها أسماء مختلفة، كما أنّها ترتبط بشكل مختلف بمكوّنات M3. في Compose، ينطبق ذلك على الفئة M2.5 Colors والفئة M3
ColorScheme والدوال ذات الصلة:
M2.5
import androidx.wear.compose.material.Colors
val appColorScheme: Colors = Colors(
// M2.5 Color parameters
)
التصميم 3
import androidx.wear.compose.material3.ColorScheme // ... val appColorScheme: ColorScheme = ColorScheme( // M3 ColorScheme parameters )
يوضّح الجدول التالي الاختلافات الرئيسية بين الإصدارَين 2.5 و3 من مقياس "إمكانية العرض":
| M2.5 | التصميم 3 |
|---|---|
Colors |
تمت إعادة تسميته إلى ColorScheme |
| 13 لونًا | 29 لونًا |
| لا ينطبق | ميزة جديدة لتطبيق المظهر بلون تفاعلي |
| لا ينطبق | ألوان ثالثية جديدة للتعبير بشكل أفضل |
تطبيق مظهر بلون تفاعلي
تتضمّن M3 ميزة جديدة هي سمات الألوان الديناميكية. إذا غيّر المستخدمون ألوان خلفية شاشة الساعة، ستتغيّر الألوان في واجهة المستخدم لتتطابق معها.
استخدِم الدالة dynamicColorScheme لتنفيذ نظام ألوان ديناميكي وتوفير defaultColorScheme كخيار احتياطي في حال عدم توفّر نظام الألوان الديناميكي.
@Composable fun myApp() { val dynamicColorScheme = dynamicColorScheme(LocalContext.current) MaterialTheme(colorScheme = dynamicColorScheme ?: myBrandColors) {} } internal val myBrandColors: ColorScheme = ColorScheme( /* Specify colors here */)
أسلوب الخط
يختلف نظام الكتابة في M3 عن M2.5 ويتضمّن الميزات التالية:
- تسعة أنماط نص جديدة
- الخطوط المرنة التي تتيح تخصيص مقاييس الخطوط لأوزان وعرض واستدارة مختلفة
AnimatedText، الذي يستخدم خطوطًا مرنة
M2.5
import androidx.wear.compose.material.Typography
val Typography = Typography(
// M2.5 TextStyle parameters
)
التصميم 3
import androidx.wear.compose.material3.Typography val Typography = Typography( // M3 TextStyle parameters )
خطوط مرنة
تتيح Flex Fonts للمصمّمين تحديد عرض الخط ووزنه لأحجام معيّنة.
أنماط النص
تتوفّر TextStyles التالية في M3. يتم استخدامها تلقائيًا من خلال العديد من مكونات M3.
| أسلوب الخط | TextStyle |
|---|---|
| الشاشة | displayLarge وdisplayMedium وdisplaySmall |
| العنوان | titleLarge, titleMedium, titleSmall |
| التصنيف | labelLarge وlabelMedium وlabelSmall |
| Body | bodyLarge وbodyMedium وbodySmall وbodyExtraSmall |
| عدد | numeralExtraLarge, numeralLarge, numeralMedium, numeralSmall, numeralExtraSmall |
| قوس | arcLarge, arcMedium, arcSmall |
الشكل
يختلف نظام الأشكال في M3 عن M2.5. زاد عدد مَعلمات الأشكال، وأصبحت أسماؤها مختلفة، كما أنّها ترتبط بشكل مختلف بمكوّنات Material Design 3. تتوفّر أحجام الأشكال التالية:
- صغير جدًا
- صغير
- متوسطة
- كبير
- كبير جدًا
في Compose، ينطبق ذلك على الفئة M2.5 Shapes والفئة M3
Shapes:
M2.5
import androidx.wear.compose.material.Shapes
val Shapes = Shapes(
// M2.5 Shapes parameters
)
التصميم 3
import androidx.wear.compose.material3.Shapes val Shapes = Shapes( // M3 Shapes parameters )
استخدِم عملية ربط مَعلمات الأشكال من نقل البيانات من Material 2 إلى Material 3 في Compose كنقطة بداية.
تغيير الشكل
تقدّم M3 ميزة "تغيير الشكل": تتغيّر الأشكال الآن استجابةً للتفاعلات.
يتوفّر سلوك "تغيير الشكل" كصيغة لعدد من الأزرار الدائرية، راجِع القائمة التالية للأزرار التي تتيح ميزة "تغيير الشكل":
| الأزرار | دالة تغيير الشكل |
|---|---|
IconButton |
تعمل السمة IconButtonDefaults.animatedShapes على تحريك زر الرمز عند الضغط عليه |
IconToggleButton |
تعمل السمة IconToggleButtonDefaults.animatedShapes على تحريك زر التبديل بين الرموز عند الضغط عليه، بينما تعمل السمة IconToggleButtonDefaults.variantAnimatedShapes على تحريك زر التبديل بين الرموز عند الضغط عليه وعند وضع علامة اختيار أو إزالتها. |
TextButton |
تعمل السمة TextButtonDefaults.animatedShapes على تحريك زر النص عند الضغط عليه |
TextToggleButton |
تعمل السمة TextToggleButtonDefaults.animatedShapes على تحريك زر التبديل النصي عند الضغط عليه، بينما تعمل السمة TextToggleButtonDefaults.variantAnimatedShapes على تحريك زر التبديل النصي عند الضغط عليه وعند وضع علامة اختيار أو إزالتها. |
المكوّنات والتنسيق
تتوفّر معظم المكوّنات والتنسيقات من M2.5 في M3. ومع ذلك، لم تكن بعض مكوّنات وتنسيقات M3 متوفّرة في M2.5. بالإضافة إلى ذلك، تتضمّن بعض مكوّنات M3 خيارات أكثر من تلك المتوفّرة في M2.5.
مع أنّ بعض المكوّنات تتطلّب مراعاة اعتبارات خاصة، يُنصح باستخدام عمليات الربط التالية بين الدوال كنقطة بداية:
في ما يلي قائمة بمكوّنات Material 3 الشائعة والمكوّنات المشابهة لها في Material 2.5:
وأخيرًا، إليك قائمة ببعض المكوّنات ذات الصلة من مكتبة Wear Compose Foundation:
| Wear Compose Foundation 1.7.0 | |
|---|---|
| androidx.wear.compose.foundation.hierarchicalFocusGroup | يُستخدَم لإضافة تعليقات توضيحية إلى العناصر القابلة للإنشاء في أحد التطبيقات، وذلك لتتبُّع الجزء النشط من التركيب وتنسيق التركيز. |
| androidx.wear.compose.foundation.pager.HorizontalPager | أداة عرض صفحات قابلة للتمرير أفقيًا، تم إنشاؤها استنادًا إلى مكوّنات Compose Foundation مع تحسينات خاصة بنظام التشغيل Wear لتحسين الأداء والالتزام بإرشادات Wear OS. |
| androidx.wear.compose.foundation.pager.VerticalPager | أداة عرض صفحات قابلة للتمرير عموديًا، تم إنشاؤها باستخدام مكوّنات Compose Foundation مع تحسينات خاصة بنظام التشغيل Wear لتحسين الأداء والالتزام بإرشادات Wear OS. |
| androidx.wear.compose.foundation.lazy.TransformingLazyColumn | يمكن استخدامها بدلاً من ScalingLazyColumn لإضافة تأثيرات تحويل التمرير إلى كل عنصر. |
الأزرار
تختلف الأزرار في M3 عن تلك في M2.5. تم استبدال شريحة M2.5 بـ
الزر. يوفر تنفيذ Button قيمًا تلقائية لكل من Text وmaxLines وtextAlign. يمكن تجاهل هذه القيم التلقائية في العنصر Text.
M2.5
import androidx.wear.compose.material.Chip
//M2.5 Buttons
Chip(...)
CompactChip(...)
Button(...)
التصميم 3
//M3 Buttons Button(onClick = { }){} CompactButton(onClick = { }){} IconButton(onClick = { }){} TextButton(onClick = { }){}
يتضمّن الإصدار M3 أيضًا أشكالاً جديدة للأزرار. يمكنك الاطّلاع عليها في نظرة عامة حول مرجع واجهة برمجة التطبيقات Compose Material 3.
تقدّم الوحدة M3 زرًا جديدًا: EdgeButton. يتوفّر EdgeButton بأربعة مقاسات مختلفة: صغير جدًا وصغير ومتوسط وكبير. توفّر عملية تنفيذ EdgeButton قيمة تلقائية لـ maxLines استنادًا إلى الحجم، ويمكن تخصيص هذه القيمة.
إذا كنت تستخدم TransformingLazyColumn أو ScalingLazyColumn، مرِّر EdgeButton إلى ScreenScaffold كي يتغيّر شكله مع التمرير بدلاً من إضافة EdgeButton كعنصر القائمة الأخير. راجِع الرمز التالي لمعرفة كيفية استخدام EdgeButton مع ScreenScaffold وTransformingLazyColumn.
val state = rememberTransformingLazyColumnState() ScreenScaffold( scrollState = state, edgeButton = { EdgeButton( onClick = { }, modifier = Modifier.scrollable( state, orientation = Orientation.Vertical, reverseDirection = true, // Apply overscroll to the EdgeButton for proper scrolling behavior. overscrollEffect = rememberOverscrollEffect(), ), ) { Text(stringResource(R.string.show)) } }, ) { contentPadding -> TransformingLazyColumn(state = state, contentPadding = contentPadding) { // additional code here // ... } }
سقالة
يختلف Scaffold في M3 عن M2.5. في الإصدار 3 من Material Design، تم استبدال AppScaffold وScreenScaffold الجديد القابل للإنشاء بـ Scaffold. تحدّد AppScaffold وScreenScaffold بنية الشاشة وتنسّق عمليات الانتقال بين المكوّنين ScrollIndicator وTimeText.
تسمح السمة AppScaffold ببقاء عناصر الشاشة الثابتة، مثل TimeText، مرئية
أثناء عمليات الانتقال داخل التطبيق، مثل التمرير سريعًا لإغلاق الشاشة. وهي توفّر مساحة مخصّصة لمحتوى التطبيق الرئيسي، والذي سيتم توفيره عادةً من خلال أحد مكونات التنقّل، مثل SwipeDismissableNavHost
عليك تعريف AppScaffold واحد للنشاط واستخدام ScreenScaffold لكل شاشة.
تضيف AppScaffold TimeTextمكوّنًا تلقائيًا إلى الشاشات. يمكنك تجاهل هذه القيمة إذا أردت تخصيصها باستخدام المَعلمة timeText.
M2.5
import androidx.wear.compose.material.Scaffold
Scaffold {...}
التصميم 3
AppScaffold { val navController = rememberSwipeDismissableNavController() SwipeDismissableNavHost( navController = navController, startDestination = "message_list" ) { composable("message_list") { MessageList(onMessageClick = { id -> navController.navigate("message_detail/$id") }) } composable("message_detail/{id}") { MessageDetail(id = it.arguments?.getString("id")!!) } } } } // Implementation of one of the screens in the navigation @Composable fun MessageDetail(id: String) { // .. Screen level content goes here val scrollState = rememberTransformingLazyColumnState() val transformationSpec = rememberTransformationSpec() ScreenScaffold( scrollState = scrollState, ) { contentPadding -> // Screen content goes here // ...
إذا كنت تستخدم HorizontalPager مع HorizontalPageIndicator، يمكنك نقل بياناتك إلى HorizontalPagerScaffold. يتم وضع HorizontalPagerScaffold داخل AppScaffold. تحدّد AppScaffold وHorizontalPagerScaffold بنية Pager وتنسّق عمليات الانتقال بين المكوّنين HorizontalPageIndicator وTimeText.
تعرض HorizontalPagerScaffold HorizontalPageIndicator في منتصف أسفل الشاشة تلقائيًا، وتنسّق عرض TimeText وHorizontalPageIndicator وإخفائهما وفقًا لما إذا كان يتم تقسيم Pager إلى صفحات، ويتم تحديد ذلك من خلال PagerState.
يتوفّر أيضًا مكوّن AnimatedPage جديد، وهو يعرض صفحة ضمن
Pager مع تأثير التوسيع والتعتيم استنادًا إلى موضعها.
AppScaffold { val pagerState = rememberPagerState(pageCount = { 10 }) HorizontalPagerScaffold(pagerState = pagerState) { HorizontalPager( state = pagerState, flingBehavior = PagerScaffoldDefaults.snapWithSpringFlingBehavior( state = pagerState ), ) { page -> AnimatedPage(pageIndex = page, pagerState = pagerState) { val columnState = rememberTransformingLazyColumnState() val transformationSpec = rememberTransformationSpec() ScreenScaffold( scrollState = columnState, ) { contentPadding -> TransformingLazyColumn( state = columnState, contentPadding = contentPadding, ) { item { ListHeader( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding( ListHeaderDefaults.minimumTopListContentPadding ), transformation = SurfaceTransformation(transformationSpec), ) { Text(text = "Pager sample") } } item { Card( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding( CardDefaults.minimumVerticalListContentPadding ), transformation = SurfaceTransformation(transformationSpec), ) { if (page == 0) { Text(text = "Page #$page. Swipe right") } else { Text(text = "Page #$page. Swipe left and right") } } } } } } } } }
أخيرًا، تقدّم M3 VerticalPagerScaffold يتبع النمط نفسه
الذي يتبعه HorizontalPagerScaffold:
@Composable fun VerticalPagerScaffoldSample() { AppScaffold { val pagerState = rememberPagerState(pageCount = { 10 }) VerticalPagerScaffold(pagerState = pagerState) { VerticalPager( state = pagerState, flingBehavior = PagerScaffoldDefaults.snapWithSpringFlingBehavior( state = pagerState ), ) { page -> AnimatedPage(pageIndex = page, pagerState = pagerState) { ScreenScaffold { Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { Text(text = "Page #$page") Spacer(modifier = Modifier.height(8.dp)) Text(text = "Swipe up and down") } } } } } } }
عنصر نائب
هناك بعض التغييرات في واجهة برمجة التطبيقات بين الإصدارين M2.5 وM3. توفّر M3 معدِّلَين للعناصر النائبة:
Modifier.placeholder، الذي يتم رسمه بدلاً من المحتوى الذي لم يتم تحميله بعد- تأثير لامع للعنصر النائب
Modifier.placeholderShimmerيوفّر تأثيرًا لامعًا للعنصر النائب يتم تشغيله في حلقة رسوم متحركة أثناء انتظار تحميل البيانات.
اطّلِع على الجدول التالي لمعرفة التغييرات الإضافية في مكوّن Placeholder.
| M2.5 | التصميم 3 |
|---|---|
PlaceholderState.startPlaceholderAnimation |
تمت إزالته |
PlaceholderState.placeholderProgression |
تمت إزالته |
PlaceholderState.isShowContent |
تم استبداله بـ PlaceholderState.isVisible (قيمة منطقية معكوسة) |
PlaceholderState.isWipeOff |
تمت إزالته |
PlaceholderDefaults.painterWithPlaceholderOverlayBackgroundBrush |
تمت إزالته |
PlaceholderDefaults.placeholderBackgroundBrush |
تمت إزالته |
PlaceholderDefaults.placeholderChipColors |
تمت إزالته |
SwipeDismissableNavHost
SwipeDismissableNavHost هو جزء من wear.compose.navigation. عند استخدام هذا المكوّن مع M3، تعدّل M3 MaterialTheme السمتَين LocalSwipeToDismissBackgroundScrimColor وLocalSwipeToDismissContentScrimColor.
TransformingLazyColumn
TransformingLazyColumn هي جزء من androidx.wear.compose.foundation.lazy وتتيح إمكانية تغيير حجم الصور المتحركة وتعديلها في عناصر القائمة أثناء التمرير، ما يؤدي إلى تحسين تجربة المستخدم. ننصح بشدة بنقل التطبيقات من ScalingLazyColumn إلى TransformingLazyColumn.
على غرار ScalingLazyColumn، يوفّر rememberTransformingLazyColumnState() لإنشاء TransformingLazyColumnState يتم تذكّره في جميع عمليات الإنشاء.
لإضافة رسوم متحركة لتغيير الحجم والشكل، أضِف ما يلي إلى كل عنصر من عناصر القائمة:
Modifier.transformedHeight، التي تتيح لك احتساب الارتفاع المحوَّل للعناصر باستخدامTransformationSpec، يمكنك استخدامrememberTransformationSpec()ما لم تكن بحاجة إلى المزيد من التخصيص.-
SurfaceTransformation
للتأكّد من أنّ المسافة المتروكة صحيحة في أعلى القائمة وأسفلها، استخدِم المعدِّل minimumVerticalContentPadding.
val columnState = rememberTransformingLazyColumnState() val transformationSpec = rememberTransformationSpec() ScreenScaffold( scrollState = columnState ) { contentPadding -> TransformingLazyColumn( state = columnState, contentPadding = contentPadding ) { item { ListHeader( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding(ListHeaderDefaults.minimumTopListContentPadding), transformation = SurfaceTransformation(transformationSpec) ) { Text(text = "Header") } } // ... other items item { Button( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding(ButtonDefaults.minimumVerticalListContentPadding), transformation = SurfaceTransformation(transformationSpec), onClick = { /* ... */ }, icon = { Icon( imageVector = Icons.Default.Build, contentDescription = "build", ) }, ) { Text( text = "Build", maxLines = 1, overflow = TextOverflow.Ellipsis, ) } } } }
روابط مفيدة
لمزيد من المعلومات حول نقل البيانات من الإصدار 2.5 إلى الإصدار 3 من Material Design في Compose، يُرجى الاطّلاع على المراجع الإضافية التالية.