تضمين رمز التنقل

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

استخراج الوجهات

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

// MyApp.kt

@Serializable
object Contacts

@Composable
fun MyApp() {
  ...
  NavHost(navController, startDestination = Contacts) {
    composable<Contacts> { ContactsScreen( /* ... */ ) }
  }
}

يجب نقل التعليمة البرمجية الخاصة بالتنقل إلى ملف منفصل:

// ContactsNavigation.kt

@Serializable
object Contacts

fun NavGraphBuilder.contactsDestination() {
    composable<Contacts> { ContactsScreen( /* ... */ ) }
}

// MyApp.kt

@Composable
fun MyApp() {
  ...
  NavHost(navController, startDestination = Contacts) {
     contactsDestination()
  }
}

أصبحت تعريفات المسارات والوجهات منفصلة الآن عن التطبيق الرئيسي فيمكنك تحديثها بشكل مستقل. يعتمد التطبيق الرئيسي على تطبيق واحد فقط . وفي هذه الحالة تكون NavGraphBuilder.contactsDestination()

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

مثال

يقدم المقتطف التالي وجهة جديدة لعرض وتفاصيل، وتحديث وجهة قائمة جهات الاتصال الحالية لكشف حدث التنقّل لعرض تفاصيل جهة الاتصال.

في ما يلي مجموعة نموذجية من الشاشات التي يمكن استخدامها internal مع الوحدة الخاصة بها، لذلك لا يمكن للوحدات الأخرى الوصول إليها:

// ContactScreens.kt

// Displays a list of contacts
@Composable
internal fun ContactsScreen(
  uiState: ContactsUiState,
  onNavigateToContactDetails: (contactId: String) -> Unit
) { ... }

// Displays the details for an individual contact
@Composable
internal fun ContactDetailsScreen(contact: ContactDetails) { ... }

إنشاء وجهات

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

يتم إجراء أحداث التنقل، مثل الانتقال إلى وجهة تفاصيل جهة الاتصال، إظهار للمتصل بدلاً من التعامل معه من خلال ViewModel.

// ContactsNavigation.kt

@Serializable
object Contacts

// Adds contacts destination to `this` NavGraphBuilder
fun NavGraphBuilder.contactsDestination(
  // Navigation events are exposed to the caller to be handled at a higher level
  onNavigateToContactDetails: (contactId: String) -> Unit
) {
  composable<Contacts> {
    // The ViewModel as a screen level state holder produces the screen
    // UI state and handles business logic for the ConversationScreen
    val viewModel: ContactsViewModel = hiltViewModel()
    val uiState = viewModel.uiState.collectAsStateWithLifecycle()
    ContactsScreen(
      uiState,
      onNavigateToContactDetails
    )
  }
}

يمكنك استخدام المنهج نفسه لإنشاء وجهة تعرض ContactDetailsScreen في هذه الحالة، بدلاً من الحصول على حالة واجهة المستخدم من نموذج العرض، فيمكنك الحصول عليه مباشرةً من NavBackStackEntry.

// ContactsNavigation.kt

@Serializable
internal data class ContactDetails(val id: String)

fun NavGraphBuilder.contactDetailsScreen() {
  composable<ContactDetails> { navBackStackEntry ->
    ContactDetailsScreen(contact = navBackStackEntry.toRoute())
  }
}

تضمين أحداث التنقّل

بالطريقة نفسها التي تُغلِّف بها الوجهات، يمكنك غلاف أحداث التنقل لتجنب الكشف عن أنواع المسارات دون داعٍ. إجراء ذلك من خلال جارٍ إنشاء دوال إضافات على NavController.

// ContactsNavigation.kt

fun NavController.navigateToContactDetails(id: String) {
  navigate(route = ContactDetails(id = id))
}

جمع البيانات معًا

رمز التنقل لعرض جهات الاتصال منفصل الآن تمامًا عن الرسم البياني للتنقل في التطبيق. يحتاج التطبيق إلى:

  • طلب دوال الإضافة NavGraphBuilder لإنشاء وجهات
  • ربط هذه الوجهات باستدعاء وظائف الإضافات NavController لأحداث التنقّل
// MyApp.kt

@Composable
fun MyApp() {
  ...
  NavHost(navController, startDestination = Contacts) {
     contactsDestination(onNavigateToContactDetails = { contactId ->
        navController.navigateToContactDetails(id = contactId)
     })
     contactDetailsDestination()
  }
}

الملخّص

  • قم بتغليف رمز التنقل لمجموعة ذات صلة من الشاشات عن طريق وضعها في ملف منفصل
  • اعرض الوجهات من خلال إنشاء وظائف إضافة على NavGraphBuilder
  • عرض أحداث التنقل من خلال إنشاء وظائف الإضافة على NavController
  • استخدِم "internal" للحفاظ على خصوصية الشاشات وأنواع المسارات.