بناء تخطيط لوحة داعمة

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

لمزيد من التفاصيل، يُرجى الاطّلاع على إرشادات اللوحة الداعمة لتصميم Material 3.

تنفيذ مساحة عرض داعمة باستخدام NavigableSupportingPaneScaffold

NavigableSupportingPaneScaffold هو عنصر قابل للتجميع يبسط تنفيذ ملف شخصي تصميم اللوحة الداعمة في Jetpack Compose. ويُغلِف الرمز SupportingPaneScaffold ويُضيف تنقّلًا مضمّنًا ومعالجة تنبؤية للرجوع.

يتيح إطار العمل الداعم للوحة ما يصل إلى ثلاث لوحات:

  • اللوحة الرئيسية: تعرِض المحتوى الأساسي.
  • اللوحة الداعمة: تقدّم سياقًا أو أدوات إضافية ذات صلة بالملف الشخصي الرئيسي.
  • لوحة إضافية (اختيارية): تُستخدَم للمحتوى الإضافي عند الحاجة.

يتم تعديل الهيكل العظمي استنادًا إلى حجم النافذة:

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

    المحتوى الرئيسي يشغل معظم الشاشة مع المحتوى الإضافي بجانبه
    الشكل 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

  • adaptive-layout: التنسيقات التكيُّفية، مثل ListDetailPaneScaffold و SupportingPaneScaffold

  • adaptive-navigation: عناصر قابلة للتجميع للتنقّل داخل ملفّات الوسائط وبينها، بالإضافة إلى تنسيقات قابلة للتكيّف تتيح التنقّل تلقائيًا، مثل NavigableListDetailPaneScaffold وNavigableSupportingPaneScaffold

تأكَّد من أنّ مشروعك يتضمّن الإصدار 1.1.0-beta1 من compose-material3-adaptive أو إصدارًا أحدث.

تفعيل ميزة "إيماءة إظهار شاشة الرجوع" التوقّعية

لتفعيل الصور المتحركة للإيماءة التنبؤية للرجوع إلى الخلف في الإصدار 15 من نظام التشغيل Android أو الإصدارات الأقدم، عليك تفعيل إيماءة الرجوع إلى الخلف التنبؤية. للموافقة، أضِف android:enableOnBackInvokedCallback="true" إلى علامة <application> أو علامات <activity> فردية في ملف AndroidManifest.xml.

بعد أن يستهدف تطبيقك الإصدار 16 من نظام التشغيل Android (المستوى 36 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، يتم تفعيل ميزة "الرجوع التوقّعي" تلقائيًا.

إنشاء أداة تنقّل

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

val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator()
val scope = rememberCoroutineScope()

تمرير المخطِّط إلى الهيكل العظمي

يتطلّب الهيكل العظمي ThreePaneScaffoldNavigator وهي واجهة represent representing the state of the scaffold، وThreePaneScaffoldValue و PaneScaffoldDirective.

NavigableSupportingPaneScaffold(
    navigator = scaffoldNavigator,
    mainPane = { /*...*/ },
    supportingPane = { /*...*/ },
)

اللوحة الرئيسية واللوحة الداعمة هما عنصران قابلان للتجميع يحتويان على المحتوى. استخدِم رمز AnimatedPane لتطبيق الصور المتحركة التلقائية للوحة أثناء التنقّل. استخدِم قيمة الإطار الفرعي للتحقّق مما إذا كانت اللوحة الداعمة مخفية. إذا كان الأمر كذلك، أظهِر زرًا يستدعي navigateTo(SupportingPaneScaffoldRole.Supporting) لعرض اللوحة الداعمة.

في ما يلي تنفيذ كامل للإطار:

val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator()
val scope = rememberCoroutineScope()

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()) {
            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(
    modifier: Modifier = Modifier,
) {
    AnimatedPane(modifier = modifier.safeContentPadding()) {
        // Supporting pane content
        Text("This is the supporting pane")
    }
}

تعمل عملية استخراج الأقسام إلى عناصر قابلة للتجميع على تبسيط استخدام SupportingPaneScaffold (قارِن ما يلي بالتنفيذ الكامل للإطار في القسم السابق):

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() },
)

إذا كنت بحاجة إلى مزيد من التحكّم في جوانب معيّنة من الإطار، ننصحك باستخدام SupportingPaneScaffold بدلاً من NavigableSupportingPaneScaffold. يقبل هذا الرمز PaneScaffoldDirective وThreePaneScaffoldValue أو ThreePaneScaffoldState بشكل منفصل. تتيح لك هذه المرونة تنفيذ منطق مخصّص لمساحة الصفيح وتحديد عدد الصفيحات التي يجب عرضها في الوقت نفسه. يمكنك أيضًا تفعيل ميزة "الرجوع التوقّعي" من خلال إضافة ThreePaneScaffoldPredictiveBackHandler.

إضافة ThreePaneScaffoldPredictiveBackHandler

إرفاق معالِج الرجوع التنبؤي الذي يأخذ مثيلًا لمحرّك التنقّل في الإطار وتحديد 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() },
)