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

تفاصيل القائمة هي نمط واجهة مستخدم يتكون من تخطيط مزدوج حيث يعرض أحد الجزء قائمة بالعناصر ويعرض الجزء الآخر تفاصيل العناصر المحددة من القائمة.

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

تنفيذ نمط واجهة المستخدم باستخدام ListDetailPaneScaffold

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

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

تعريف التبعيات

ListDetailPaneScaffold هي جزء من مكتبة Material 3 التكيّفية. أضِف تبعية للمكتبة في ملف build.gradle لتطبيقك أو الوحدة:

implementation("androidx.compose.material3.adaptive:adaptive:1.0.0-alpha07")
implementation("androidx.compose.material3.adaptive:adaptive-layout:1.0.0-alpha07")
implementation("androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-alpha07")

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

يوضِّح ما يلي الاستخدام الأساسي لـ ListDetailPaneScaffold:

  1. تخزين العنصر المحدد حاليًا من القائمة بمتغير حالة قابل للتغيير. يحمل المتغير العنصر ليتم عرضه في جزء التفاصيل. عادةً ما تريد إعداد العنصر المحدّد حاليًا باستخدام null، مع الإشارة إلى عدم إجراء أي اختيار بعد.

    class MyItem(val id: Int) {
        companion object {
            val Saver: Saver<MyItem?, Int> = Saver(
                { it?.id },
                ::MyItem,
            )
        }
    }

    var selectedItem: MyItem? by rememberSaveable(stateSaver = MyItem.Saver) {
        mutableStateOf(null)
    }

  2. إنشاء ThreePaneScaffoldNavigator باستخدام rememberListDetailPaneScaffoldNavigator وإضافة BackHandler. يُستخدم المستكشف هذا للتنقل بين القائمة والتفاصيل والأجزاء الإضافية، وتوفير الحالة للسقالة. توفّر BackHandler المُضافة إمكانية الرجوع إلى الخلف باستخدام زر الرجوع أو إيماءة الرجوع إلى النظام. إنّ السلوك المتوقّع لزر الرجوع في ListDetailPaneScaffold يعتمد على حجم النافذة والقيمة الحالية للسقّالة. إذا كان بإمكان ListDetailPaneScaffold السماح بالعودة إلى الحالة الحالية، سيكون canNavigateBack() هو true، مع تفعيل BackHandler.

    val navigator = rememberListDetailPaneScaffoldNavigator<Nothing>()
    
    BackHandler(navigator.canNavigateBack()) {
        navigator.navigateBack()
    }

  3. انقل scaffoldState من navigator الذي أنشأته إلى العنصر ListDetailPaneScaffold القابل للإنشاء.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        // ...
    )

  4. وفِّر عملية تنفيذ لوحة القائمة إلى ListDetailPaneScaffold. تأكَّد من أنّ عملية التنفيذ تتضمّن وسيطة استدعاء لتسجيل العنصر المحدّد حديثًا. عند تفعيل معاودة الاتصال هذه، عدِّل متغيّر الحالة "selectedItem" واستخدِم ThreePaneScaffoldNavigator لعرض جزء التفاصيل (ListDetailPaneScaffoldRole.Detail).

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane = {
            AnimatedPane(Modifier) {
                MyList(
                    onItemClick = { id ->
                        // Set current item
                        selectedItem = id
                        // Switch focus to detail pane
                        navigator.navigateTo(ListDetailPaneScaffoldRole.Detail)
                    }
                )
            }
        },
        // ...
    )

  5. يمكنك تضمين تنفيذ لوحة التفاصيل في ListDetailPaneScaffold. يمكنك عرض محتوى التفاصيل فقط إذا لم تكن قيمة selectedItem فارغة.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane =
        // ...
        detailPane = {
            AnimatedPane(Modifier) {
                selectedItem?.let { item ->
                    MyDetails(item)
                }
            }
        },
    )

بعد تنفيذ الخطوات المذكورة أعلاه، يجب أن تبدو التعليمة البرمجية على النحو التالي:

// Currently selected item
var selectedItem: MyItem? by rememberSaveable(stateSaver = MyItem.Saver) {
    mutableStateOf(null)
}

// Create the ListDetailPaneScaffoldState
val navigator = rememberListDetailPaneScaffoldNavigator<Nothing>()

BackHandler(navigator.canNavigateBack()) {
    navigator.navigateBack()
}

ListDetailPaneScaffold(
    directive = navigator.scaffoldDirective,
    value = navigator.scaffoldValue,
    listPane = {
        AnimatedPane(Modifier) {
            MyList(
                onItemClick = { id ->
                    // Set current item
                    selectedItem = id
                    // Display the detail pane
                    navigator.navigateTo(ListDetailPaneScaffoldRole.Detail)
                },
            )
        }
    },
    detailPane = {
        AnimatedPane(Modifier) {
            // Show the detail pane content if selected item is available
            selectedItem?.let { item ->
                MyDetails(item)
            }
        }
    },
)