Material 3 Expressive هو الإصدار التالي من التصميم المتعدد الأبعاد. ويتضمن ذلك ميزات محدّثة للمظاهر والمكونات والتخصيص، مثل اللون الديناميكي.
يركّز هذا الدليل على نقل البيانات من مكتبة Jetpack Wear Compose Material 2.5 (androidx.wear.compose) إلى مكتبة Jetpack Wear Compose Material 3 (androidx.wear.compose.material3) للتطبيقات.
الأساليب
لنقل رمز تطبيقك من 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.8.0-alpha03")
يمكنك الاطّلاع على أحدث إصدارات M3 في صفحة إصدارات Wear Compose.
يقدّم الإصدار 1.8.0-alpha03 من مكتبة Wear Compose Foundation بعض المكوّنات الجديدة المصمّمة للعمل مع مكوّنات Material 3.
وبالمثل، تم تعديل الحركة في SwipeDismissableNavHost من مكتبة Wear Compose Navigation عند تشغيلها على Wear OS 6 (مستوى واجهة برمجة التطبيقات 36) أو الإصدارات الأحدث. عند
التحديث إلى الإصدار 3 من Wear Compose Material، ننصح أيضًا بتحديث مكتبتَي Wear
Compose Foundation وNavigation:
implementation("androidx.wear.compose:compose-foundation:1.8.0-alpha03")
implementation("androidx.wear.compose:compose-navigation:1.8.0-alpha03")
المظهر
في كل من 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 )
يوضّح الجدول التالي الاختلافات الرئيسية بين M2.5 وM3:
| 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 للمصممين تحديد عرض الخط ووزنه لأحجام معينة.
أنماط النص
تتوفّر 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. زاد عدد مَعلمات الأشكال، وتمت تسميتها بشكل مختلف، وتم ربطها بشكل مختلف بمكوّنات M3. تتوفّر أحجام الأشكال التالية:
- صغيرة جدًا
- صغير
- متوسطة
- كبير
- كبير جدًا
في 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 )
استخدِم تعيين مَعلمات الأشكال من Migrate من Material 2 إلى Material 3 في Compose كنقطة بداية.
تحويل الشكل
يقدّم M3 ميزة "تغيير الشكل" (Shape Morphing): تتغيّر الأشكال الآن استجابةً للتفاعلات.
يتوفّر سلوك "تغيير الشكل" كصيغة لعدد من الأزرار الدائرية، ويمكنك الاطّلاع على قائمة الأزرار التالية التي تتيح "تغيير الشكل":
| الأزرار | ميزة تحويل الأشكال |
|---|---|
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:
| الإصدار 1.8.0-alpha03 من Wear Compose Foundation | |
|---|---|
| androidx.wear.compose.foundation.hierarchicalFocusGroup | يُستخدَم لإضافة تعليقات توضيحية إلى الدوال المركّبة في أحد التطبيقات، وذلك لتتبُّع الجزء النشط من التركيب وتنسيق التركيز. |
| androidx.wear.compose.foundation.pager.HorizontalPager | هو عنصر تنقّل بين الصفحات يتم تمريره أفقيًا، ويستند إلى مكوّنات Compose Foundation مع تحسينات خاصة بالأجهزة القابلة للارتداء لتحسين الأداء والالتزام بإرشادات 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 implementation provides default values for Text
maxLines and 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
implementation provide a default value for maxLines depending on the size
which can be customized.
إذا كنت تستخدم 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
يختلف Scaffold في M3 عن M2.5. في M3، تم استبدال Scaffold بـ AppScaffold والدالة المركّبة الجديدة ScreenScaffold. يحدّد 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 بنية "التنقّل بين الصفحات" وينسّقان عمليات الانتقال بين مكوّنات HorizontalPageIndicator وTimeText.
يعرض HorizontalPagerScaffold HorizontalPageIndicator في
منتصف نهاية الشاشة تلقائيًا وينسّق عرض وإخفاء
TimeText وHorizontalPageIndicator وفقًا لما إذا كان Pager
يتم التنقّل بين صفحاته، ويتم تحديد ذلك من خلال PagerState.
هناك أيضًا مكوّن AnimatedPage جديد يحرّك صفحة ضمن "التنقّل بين الصفحات" مع تأثير تغيير الحجم والتعتيم استنادًا إلى موضعها.
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, ) } } } }
روابط مفيدة
لمزيد من المعلومات حول نقل البيانات من M2.5 إلى M3 في Compose، يُرجى الاطّلاع على المراجع الإضافية التالية.