وصفة تفصيلية لقائمة المواد
توضّح هذه الوصفة كيفية إنشاء تصميم متجاوب على شكل قائمة مع تفاصيل باستخدام ListDetailSceneStrategy من مكتبة Material 3 Adaptive. يتم تعديل هذا التصميم تلقائيًا لعرض جزء واحد أو جزأين أو ثلاثة أجزاء حسب عرض الشاشة المتاح.
طريقة العمل
يتضمّن هذا المثال ثلاث وجهات: ConversationList وConversationDetail وProfile.
ListDetailSceneStrategy
مفتاح هذه الوصفة هو rememberListDetailSceneStrategy، الذي يوفّر منطق التصميم التكيّفي.
-
أدوار اللوحة: يتمّ تحديد دور لكلّ وجهة باستخدام البيانات الوصفية:
-
ListDetailSceneStrategy.listPane(): للمحتوى الأساسي (القائمة) يكون هذا الجزء مرئيًا دائمًا. يمكن توفير عنصر نائب ليتم عرضه في مساحة لوحة التفاصيل عندما لا يتم تحديد أي محتوى تفصيلي. -
ListDetailSceneStrategy.detailPane(): بالنسبة إلى المحتوى الثانوي (التفصيلي) -
ListDetailSceneStrategy.extraPane(): للمحتوى الثانوي
-
-
التنسيق التكيّفي: يتعامل
ListDetailSceneStrategyتلقائيًا مع التنسيق. على الشاشات الأصغر حجمًا، لا يظهر سوى جزء واحد في كل مرة. على الشاشات الأوسع، سيتم عرض لوحتي القائمة والتفاصيل جنبًا إلى جنب. على الشاشات العريضة جدًا، يمكن عرض جميع اللوحات الثلاث: القائمة والتفاصيل والمعلومات الإضافية. -
التنقّل: يتم التنقّل بين اللوحات من خلال إضافة الوجهات وإزالتها من سجلّ الرجوع كالمعتاد. يراقب
ListDetailSceneStrategyسجلّ الرجوع ويعدّل التنسيق وفقًا لذلك.
package com.example.nav3recipes.material.listdetail /* * Copyright 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.Column import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi import androidx.compose.material3.adaptive.currentWindowAdaptiveInfoV2 import androidx.compose.material3.adaptive.layout.calculatePaneScaffoldDirective import androidx.compose.material3.adaptive.navigation3.ListDetailSceneStrategy import androidx.compose.material3.adaptive.navigation3.rememberListDetailSceneStrategy import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.dropUnlessResumed import androidx.navigation3.runtime.NavKey import androidx.navigation3.runtime.entryProvider import androidx.navigation3.runtime.rememberNavBackStack import androidx.navigation3.ui.NavDisplay import com.example.nav3recipes.content.ContentBlue import com.example.nav3recipes.content.ContentGreen import com.example.nav3recipes.content.ContentRed import com.example.nav3recipes.content.ContentYellow import com.example.nav3recipes.ui.setEdgeToEdgeConfig import kotlinx.serialization.Serializable @Serializable private object ConversationList : NavKey @Serializable private data class ConversationDetail(val id: String) : NavKey @Serializable private data object Profile : NavKey class MaterialListDetailActivity : ComponentActivity() { @OptIn(ExperimentalMaterial3AdaptiveApi::class) override fun onCreate(savedInstanceState: Bundle?) { setEdgeToEdgeConfig() super.onCreate(savedInstanceState) setContent { val backStack = rememberNavBackStack(ConversationList) // Override the defaults so that there isn't a horizontal space between the panes. // See b/418201867 val windowAdaptiveInfo = currentWindowAdaptiveInfoV2() val directive = remember(windowAdaptiveInfo) { calculatePaneScaffoldDirective(windowAdaptiveInfo) .copy(horizontalPartitionSpacerSize = 0.dp) } val listDetailStrategy = rememberListDetailSceneStrategy<NavKey>(directive = directive) NavDisplay( backStack = backStack, onBack = { backStack.removeLastOrNull() }, sceneStrategies = listOf(listDetailStrategy), entryProvider = entryProvider { entry<ConversationList>( metadata = ListDetailSceneStrategy.listPane( detailPlaceholder = { ContentYellow("Choose a conversation from the list") } ) ) { ContentRed("Welcome to Nav3") { Button(onClick = dropUnlessResumed { backStack.add(ConversationDetail("ABC")) }) { Text("View conversation") } } } entry<ConversationDetail>( metadata = ListDetailSceneStrategy.detailPane() ) { conversation -> ContentBlue("Conversation ${conversation.id} ") { Column(horizontalAlignment = Alignment.CenterHorizontally) { Button(onClick = dropUnlessResumed { backStack.add(Profile) }) { Text("View profile") } } } } entry<Profile>( metadata = ListDetailSceneStrategy.extraPane() ) { ContentGreen("Profile") } } ) } } }