إنشاء تخطيط على تفاصيل القائمة

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

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

لوحة تفاصيل تظهر بجانب صفحة القائمة
الشكل 1. عند توفّر مساحة كافية على الشاشة، تظهر لوحة التفاصيل بجانب لوحة القائمة.
بعد اختيار عنصر، ستشغل لوحة التفاصيل الشاشة بأكملها.
الشكل 2. عندما تكون مساحة الشاشة محدودة، تشغل لوحة التفاصيل المساحة بأكملها (لأنّه تم اختيار عنصر)

تنفيذ نمط "قائمة-تفاصيل" باستخدام NavigableListDetailPaneScaffold

NavigableListDetailPaneScaffold هو عنصر قابل للإنشاء يسهّل تنفيذ عرض على شكل قائمة مع تفاصيل في Jetpack Compose. وهو يغلّف ListDetailPaneScaffold ويضيف صورًا متحركة مدمجة للتنقّل وإيماءة إظهار شاشة الرجوع.

تتيح سقالة "عرض على شكل قائمة مع تفاصيل" ما يصل إلى ثلاث لوحات:

  1. لوحة القائمة: تعرض مجموعة من العناصر.
  2. لوحة التفاصيل: تعرض تفاصيل عنصر محدّد.
  3. لوحة إضافية (اختيارية): تقدّم سياقًا إضافيًا عند الحاجة.

تتكيّف السقالة استنادًا إلى حجم النافذة:

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

تحديد الاعتماديات

NavigableListDetailPaneScaffold هو جزء من مكتبة التنقّل التكيّفي في 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'
  • ‫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. لمزيد من المعلومات، يُرجى الاطّلاع على مقالة الموافقة على استخدام إيماءة إظهار شاشة الرجوع.

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

الاستخدام الأساسي

نفِّذ NavigableListDetailPaneScaffold على النحو التالي:

  1. استخدِم فئة تمثّل المحتوى المحدّد. استخدِم Parcelable فئة لدعم حفظ عنصر القائمة المحدّد واستعادته. استخدِم مكوّن kotlin-parcelize الإضافي لإنشاء الرمز البرمجي نيابةً عنك.
  2. أنشِئ ThreePaneScaffoldNavigator باستخدام rememberListDetailPaneScaffoldNavigator.

يُستخدَم هذا المتصفّح للتنقّل بين لوحات القائمة والتفاصيل واللوحة الإضافية. من خلال تحديد نوع عام، يتتبّع المتصفّح أيضًا حالة السقالة (أي MyItem الذي يتم عرضه). بما أنّ هذا النوع قابل للتجزئة، يمكن للمتصفّح حفظ الحالة واستعادتها للتعامل تلقائيًا مع تغييرات الإعدادات.

  1. مرِّر المتصفّح إلى العنصر القابل للإنشاء NavigableListDetailPaneScaffold.

  2. قدِّم تنفيذ لوحة القائمة إلى NavigableListDetailPaneScaffold. استخدِم AnimatedPane لتطبيق الصور المتحركة التلقائية للوحة أثناء التنقّل. بعد ذلك، استخدِم ThreePaneScaffoldNavigator للانتقال إلى لوحة التفاصيل، وListDetailPaneScaffoldRole.Detail، وعرض العنصر الذي تم تمريره.

  3. أدرِج تنفيذ لوحة التفاصيل في NavigableListDetailPaneScaffold.

عند اكتمال التنقّل، يحتوي currentDestination على اللوحة التي انتقل إليها تطبيقك، بما في ذلك المحتوى المعروض في اللوحة. يكون نوع السمة contentKey هو النوع نفسه المحدّد في الاستدعاء الأصلي، ما يتيح لك الوصول إلى أي بيانات تحتاج إلى عرضها.

  1. يمكنك اختياريًا تغيير defaultBackBehavior في NavigableListDetailPaneScaffold. تلقائيًا، تستخدِم NavigableListDetailPaneScaffold الخيار PopUntilScaffoldValueChange للسمة defaultBackBehavior.

إذا كان تطبيقك يتطلب نمطًا مختلفًا للتنقّل للخلف، يمكنك إلغاء هذا السلوك من خلال تحديد خيار آخر من BackNavigationBehavior.

خيارات BackNavigationBehavior

يستخدِم القسم التالي مثالاً على تطبيق بريد إلكتروني يتضمّن قائمة بالرسائل الإلكترونية في لوحة واحدة وعرضًا تفصيليًا في اللوحة الأخرى.

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

انظر إلى الأمثلة التالية:

  • متعدد اللوحات: أنت تعرض رسالة إلكترونية (العنصر 1) في لوحة التفاصيل. يؤدي النقر على رسالة إلكترونية أخرى (العنصر 2) إلى تعديل لوحة التفاصيل، ولكن تظل لوحتا القائمة والتفاصيل ظاهرتَين. قد يؤدي الضغط على زر الرجوع إلى الخروج من التطبيق أو من مسار التنقّل الحالي.
  • لوحة واحدة: أنت تعرض العنصر 1، ثم العنصر 2، وسيؤدي الضغط على زر الرجوع إلى إعادتك مباشرةً إلى لوحة قائمة عناوين البريد الإلكتروني.

استخدِم هذا الخيار عندما تريد أن يلاحظ المستخدمون عمليات انتقال واضحة في التنسيق مع كل إجراء رجوع.

تغيير قيمة التنقّل
PopUntilContentChange

يركّز هذا السلوك على المحتوى المعروض. إذا عرضت العنصر 1 ثم العنصر 2، سيؤدي الضغط على زر الرجوع إلى الرجوع إلى العنصر 1، بغض النظر عن التنسيق.

انظر إلى الأمثلة التالية:

  • متعدد اللوحات: أنت تعرض العنصر 1 في لوحة التفاصيل، ثم تنقر على العنصر 2 في القائمة. يتم تعديل لوحة التفاصيل. سيؤدي الضغط على زر الرجوع إلى استعادة لوحة التفاصيل إلى العنصر 1.
  • لوحة واحدة: يحدث الرجوع إلى المحتوى نفسه.

استخدِم هذا الخيار عندما يتوقّع المستخدم الرجوع إلى المحتوى الذي تم عرضه سابقًا عند الضغط على زر الرجوع.

الانتقال بين لوحتَي تفاصيل
PopUntilCurrentDestinationChange

يؤدي هذا السلوك إلى إزالة العناصر من مكدس الرجوع إلى الخلف إلى أن يتغيّر وجهة التنقّل الحالية. وينطبق ذلك بالتساوي على تنسيقات اللوحة الواحدة واللوحات المتعددة.

انظر إلى الأمثلة التالية:

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

استخدِم هذا الخيار عندما يكون الحفاظ على مؤشر مرئي واضح للتنقّل الحالي أمرًا بالغ الأهمية لتجربة المستخدم.

التنقّل بين لوحَي التفاصيل والقائمة
PopLatest

يزيل هذا الخيار الوجهة الأحدث فقط من مكدس الرجوع إلى الخلف. استخدِم هذا الخيار للتنقّل للخلف بدون تخطّي الحالات الوسيطة.

بعد تنفيذ هذه الخطوات، من المفترض أن يبدو الرمز البرمجي مشابهًا لما يلي:

NavigableListDetailPaneScaffold(
    navigator = navigator,
    listPane = {
        AnimatedPane {
            ListContent(
                words = sampleWords,
                selectionState = navigator.currentDestination?.contentKey?.let {
                    SelectionVisibilityState.ShowSelection(it)
                } ?: SelectionVisibilityState.NoSelection,
                onWordClick = { word ->
                    scope.launch {
                        navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, word)
                    }
                },
                animatedVisibilityScope = this@AnimatedPane,
                sharedTransitionScope = this@SharedTransitionLayout
            )
        }
    },
    detailPane = {
        AnimatedPane {
            DetailContent(
                definedWord = navigator.currentDestination?.contentKey,
                animatedVisibilityScope = this@AnimatedPane,
                sharedTransitionScope = this@SharedTransitionLayout,
                onClosePane = {
                    scope.launch {
                        navigator.navigateBack(
                            backNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange
                        )

                    }
                }
            )
        }
    }