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

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

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

تنفيذ لوحة داعمة باستخدام هيكل

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")

Groovy

implementation 'androidx.compose.material3.adaptive:adaptive'
implementation 'androidx.compose.material3.adaptive:adaptive-layout'
implementation 'androidx.compose.material3.adaptive:adaptive-navigation'
  • adaptive: الوحدات الأساسية المنخفضة المستوى، مثل HingeInfo وPosture

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

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

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

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

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

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

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

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

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

تمرير أداة التنقّل إلى أداة إنشاء البنية الأساسية

يتطلّب التصميم الأساسي ThreePaneScaffoldNavigator، وهو واجهة تمثّل حالة التصميم الأساسي، و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() },
)