يحافظ تنسيق اللوحة الثانوية على تركيز المستخدم على المحتوى الرئيسي للتطبيق مع عرض معلومات ثانوية ذات صلة. على سبيل المثال، قد تعرض اللوحة الرئيسية تفاصيل حول فيلم، بينما تسرد اللوحة الثانوية أفلامًا مشابهة أو أفلامًا من إخراج المُخرج نفسه أو أعمالاً تضم الممثلين أنفسهم.
لمزيد من التفاصيل، اطّلِع على إرشادات اللوحة الثانوية في Material 3.
تنفيذ لوحة ثانوية باستخدام عنصر `Scaffold`
NavigableSupportingPaneScaffold هو عنصر مركّب يسهّل تنفيذ تنسيق لوحة ثانوية في Jetpack Compose. وهو يغلّف
SupportingPaneScaffold ويضيف معالجة مدمجة للتنقّل وإيماءة إظهار شاشة الرجوع.
يمكن أن يتضمّن عنصر `Scaffold` للوحة الثانوية ما يصل إلى ثلاث لوحات:
- اللوحة الرئيسية: تعرض المحتوى الأساسي.
- اللوحة الثانوية: تقدّم سياقًا أو أدوات إضافية ذات صلة باللوحة الرئيسية.
- اللوحة الإضافية (اختيارية): تُستخدم لعرض محتوى تكميلي عند الحاجة.
يتكيّف عنصر `Scaffold` استنادًا إلى حجم النافذة:
- في النوافذ الكبيرة، تظهر اللوحتان الرئيسية والثانوية جنبًا إلى جنب.
في النوافذ الصغيرة، لا تظهر سوى لوحة واحدة في كل مرة، ويتم التبديل بين اللوحات أثناء تنقّل المستخدمين.
الشكل 1. تنسيق اللوحة الثانوية
إضافة التبعيات
NavigableSupportingPaneScaffold هو جزء من مكتبة التنسيقات التكيّفية في Material 3.
أضِف التبعيات الثلاث ذات الصلة التالية إلى ملف build.gradle الخاص بتطبيقك أو وحدتك:
Kotlin
implementation("androidx.compose.material3.adaptive:adaptive")
implementation("androidx.compose.material3.adaptive:adaptive-layout")
implementation("androidx.compose.material3.adaptive:adaptive-navigation")
أنيق
implementation 'androidx.compose.material3.adaptive:adaptive'
implementation 'androidx.compose.material3.adaptive:adaptive-layout'
implementation 'androidx.compose.material3.adaptive:adaptive-navigation'
تكيّفي: وحدات أساسية منخفضة المستوى، مثل
HingeInfoوPostureتنسيق تكيّفي: تنسيقات تكيّفية، مثل
ListDetailPaneScaffoldوSupportingPaneScaffoldتنقّل تكيّفي: عناصر مركّبة للتنقّل داخل اللوحات وبينها، بالإضافة إلى تنسيقات تكيّفية تتيح التنقّل تلقائيًا، مثل
NavigableListDetailPaneScaffoldوNavigableSupportingPaneScaffold
تأكَّد من أنّ مشروعك يتضمّن الإصدار 1.1.0-beta1 أو إصدارًا أحدث من مكتبة compose-material3-adaptive.
تفعيل إيماءة إظهار شاشة الرجوع
لتفعيل الصور المتحركة لإيماءة إظهار شاشة الرجوع في Android 15 أو الإصدارات الأقدم، عليك الموافقة على استخدام هذه الإيماءة. للموافقة، أضِف
android:enableOnBackInvokedCallback="true" إلى علامة <application> أو
علامات <activity> الفردية ضمن ملف AndroidManifest.xml.
عندما يستهدف تطبيقك Android 16 (المستوى 36 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، يتم تفعيل إيماءة إظهار شاشة الرجوع تلقائيًا.
إنشاء أداة تنقّل
في النوافذ الصغيرة، لا تظهر سوى لوحة واحدة في كل مرة، لذا استخدِم
ThreePaneScaffoldNavigator للانتقال إلى اللوحات ومنها. أنشئ مثيلاً
لأداة التنقّل باستخدام rememberSupportingPaneScaffoldNavigator.
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() val scope = rememberCoroutineScope()
تمرير أداة التنقّل إلى عنصر `Scaffold`
يتطلّب عنصر `Scaffold` أداة ThreePaneScaffoldNavigator، وهي واجهة
تمثّل حالة عنصر `Scaffold` وThreePaneScaffoldValue و
PaneScaffoldDirective.
NavigableSupportingPaneScaffold( navigator = scaffoldNavigator, mainPane = { /*...*/ }, supportingPane = { /*...*/ }, )
اللوحة الرئيسية واللوحة الثانوية هما عنصران مركّبان يحتويان على المحتوى. استخدِم
AnimatedPane لتطبيق الصور المتحركة التلقائية للوحة أثناء التنقّل. استخدِم
قيمة عنصر `Scaffold` للتحقّق مما إذا كانت اللوحة الثانوية مخفية. إذا كانت كذلك،
اعرض زرًا يستدعي
navigateTo(SupportingPaneScaffoldRole.Supporting) لعرض
اللوحة الثانوية.
بالنسبة إلى الشاشات الكبيرة، استخدِم الـ ThreePaneScaffoldNavigator.navigateBack()
method لإغلاق اللوحة الثانوية، مع تمرير الـ
BackNavigationBehavior.PopUntilScaffoldValueChange constant. يؤدي استدعاء هذه
الطريقة إلى إعادة إنشاء NavigableSupportingPaneScaffold.
أثناء إعادة الإنشاء، تحقَّق من السمة
ThreePaneScaffoldNavigator.currentDestination لتحديد ما إذا كان يجب عرض اللوحة الثانوية.
في ما يلي عملية تنفيذ كاملة لعنصر `Scaffold`:
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() val scope = rememberCoroutineScope() val backNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange NavigableSupportingPaneScaffold( navigator = scaffoldNavigator, mainPane = { AnimatedPane( modifier = Modifier .safeContentPadding() .background(Color.Red) ) { if (scaffoldNavigator.scaffoldValue[SupportingPaneScaffoldRole.Supporting] == PaneAdaptedValue.Hidden) { Button( modifier = Modifier .wrapContentSize(), onClick = { scope.launch { scaffoldNavigator.navigateTo(SupportingPaneScaffoldRole.Supporting) } } ) { Text("Show supporting pane") } } else { Text("Supporting pane is shown") } } }, supportingPane = { AnimatedPane(modifier = Modifier.safeContentPadding()) { Column { // Allow users to dismiss the supporting pane. Use back navigation to // hide an expanded supporting pane. if (scaffoldNavigator.scaffoldValue[SupportingPaneScaffoldRole.Supporting] == PaneAdaptedValue.Expanded) { // Material design principles promote the usage of a right-aligned // close (X) button. IconButton( modifier = Modifier.align(Alignment.End).padding(16.dp), onClick = { scope.launch { scaffoldNavigator.navigateBack(backNavigationBehavior) } } ) { Icon(Icons.Default.Close, contentDescription = "Close") } } Text("Supporting pane") } } } )
استخراج العناصر المركّبة للوحة
استخرِج اللوحات الفردية من SupportingPaneScaffold إلى عناصر مركّبة خاصة بها لجعلها قابلة لإعادة الاستخدام والاختبار. استخدِم ThreePaneScaffoldScope
للوصول إلى AnimatedPane إذا كنت تريد استخدام الصور المتحركة التلقائية:
@OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable fun ThreePaneScaffoldPaneScope.MainPane( shouldShowSupportingPaneButton: Boolean, onNavigateToSupportingPane: () -> Unit, modifier: Modifier = Modifier, ) { AnimatedPane( modifier = modifier.safeContentPadding() ) { // Main pane content if (shouldShowSupportingPaneButton) { Button(onClick = onNavigateToSupportingPane) { Text("Show supporting pane") } } else { Text("Supporting pane is shown") } } } @OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable fun ThreePaneScaffoldPaneScope.SupportingPane( scaffoldNavigator: ThreePaneScaffoldNavigator<Any>, modifier: Modifier = Modifier, backNavigationBehavior: BackNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange, ) { val scope = rememberCoroutineScope() AnimatedPane(modifier = Modifier.safeContentPadding()) { Column { // Allow users to dismiss the supporting pane. Use back navigation to // hide an expanded supporting pane. if (scaffoldNavigator.scaffoldValue[SupportingPaneScaffoldRole.Supporting] == PaneAdaptedValue.Expanded) { // Material design principles promote the usage of a right-aligned // close (X) button. IconButton( modifier = modifier.align(Alignment.End).padding(16.dp), onClick = { scope.launch { scaffoldNavigator.navigateBack(backNavigationBehavior) } } ) { Icon(Icons.Default.Close, contentDescription = "Close") } } Text("Supporting pane") } } }
يؤدي استخراج اللوحات إلى عناصر مركّبة إلى تبسيط استخدام SupportingPaneScaffold (قارِن ما يلي بالتنفيذ الكامل لعنصر `Scaffold` في القسم السابق):
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() val scope = rememberCoroutineScope() NavigableSupportingPaneScaffold( navigator = scaffoldNavigator, mainPane = { MainPane( shouldShowSupportingPaneButton = scaffoldNavigator.scaffoldValue.secondary == PaneAdaptedValue.Hidden, onNavigateToSupportingPane = { scope.launch { scaffoldNavigator.navigateTo(ThreePaneScaffoldRole.Secondary) } } ) }, supportingPane = { SupportingPane(scaffoldNavigator = scaffoldNavigator) }, )
إذا كنت بحاجة إلى مزيد من التحكّم في جوانب معيّنة من عنصر `Scaffold`، ننصحك باستخدام
SupportingPaneScaffold بدلاً من NavigableSupportingPaneScaffold. يقبل هذا العنصر
PaneScaffoldDirective وThreePaneScaffoldValue أو
ThreePaneScaffoldState بشكل منفصل. تتيح لك هذه المرونة تنفيذ منطق مخصّص لتباعد اللوحات وتحديد عدد اللوحات التي يجب عرضها في وقت واحد. يمكنك أيضًا تفعيل إيماءة إظهار شاشة الرجوع من خلال إضافة ThreePaneScaffoldPredictiveBackHandler.
إضافة ThreePaneScaffoldPredictiveBackHandler
أرفِق معالج إيماءة إظهار شاشة الرجوع الذي يأخذ مثيلاً لأداة تنقّل عنصر `Scaffold` وحدِّد backBehavior. يحدّد هذا الخيار كيفية إزالة الوجهات من سجلّ التتبّع أثناء التنقّل للرجوع. بعد ذلك، مرِّر scaffoldDirective وscaffoldState إلى SupportingPaneScaffold. استخدِم الحمل الزائد الذي يقبل ThreePaneScaffoldState، مع تمرير scaffoldNavigator.scaffoldState.
حدِّد اللوحتَين الرئيسية والثانوية ضمن SupportingPaneScaffold. استخدِم AnimatedPane للصور المتحركة التلقائية للوحة.
بعد تنفيذ هذه الخطوات، من المفترض أن يظهر الرمز البرمجي على النحو التالي:
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() val scope = rememberCoroutineScope() ThreePaneScaffoldPredictiveBackHandler( navigator = scaffoldNavigator, backBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange ) SupportingPaneScaffold( directive = scaffoldNavigator.scaffoldDirective, scaffoldState = scaffoldNavigator.scaffoldState, mainPane = { MainPane( shouldShowSupportingPaneButton = scaffoldNavigator.scaffoldValue.secondary == PaneAdaptedValue.Hidden, onNavigateToSupportingPane = { scope.launch { scaffoldNavigator.navigateTo(ThreePaneScaffoldRole.Secondary) } } ) }, supportingPane = { SupportingPane(scaffoldNavigator = scaffoldNavigator) }, )