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

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

لمزيد من التفاصيل، يُرجى الاطّلاع على إرشادات لوحة المساندة لمواد العرض 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 أو إصدارًا أحدث.

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

لتفعيل الصور المتحركة للإيماءة التنبؤية للرجوع إلى الخلف في Android 15 أو الإصدارات الأقدم، عليك تفعيل ميزة إتاحة إيماءة الرجوع إلى الخلف التنبؤية. للموافقة، أضِف android:enableOnBackInvokedCallback="true" إلى <application> [العلامة أو 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() },
)