تصميم الرسم البياني للتنقل

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

أنواع الوجهة

هناك ثلاثة أنواع عامة من الوجهات: المستضافة ومربّع الحوار والنشاط. يوضّح الجدول التالي أنواع الوجهات الثلاثة هذه والغرض منها.

Type

الوصف

حالات الاستخدام

مستضاف

يملأ مضيف التنقل بالكامل. وهذا يعني أنّ حجم وجهة مستضافة يكون مماثلاً لحجم مضيف التنقّل ولا تكون الوجهات السابقة مرئية.

الشاشة الرئيسية وشاشات التفاصيل.

مربّع حوار

تعرض مكونات واجهة المستخدم المتراكبة. ولا ترتبط واجهة المستخدم هذه بالموقع الجغرافي لمضيف التنقّل أو حجمه. تظهر الوجهات السابقة أسفل الوجهة.

التنبيهات والتحديدات والنماذج.

النشاط

يمثل شاشات أو ميزات فريدة داخل التطبيق.

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

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

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

أُطر العمل

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

  • الإنشاء: استخدِم عنصر NavHost القابل للإنشاء. أضِف NavGraph إليها باستخدام Kotlin DSL. يمكنك إنشاء الرسم البياني بطريقتين:
    • كجزء من NavHost: يمكنك إنشاء الرسم البياني للتنقل مباشرةً كجزء من إضافة NavHost.
    • آليًا: استخدِم الطريقة NavController.createGraph() لإنشاء NavGraph وتمريره إلى NavHost مباشرةً.
  • الأجزاء: عند استخدام الأجزاء مع إطار عمل واجهة المستخدم لطرق العرض، استخدِم NavHostFragment كمضيف. تتوفّر عدة طرق لإنشاء رسم بياني للتنقّل:
    • بشكل آلي: يمكنك استخدام Kotlin DSL لإنشاء NavGraph وتطبيقه مباشرةً على NavHostFragment.
      • الدالة createGraph() المستخدمة مع Kotlin DSL لكل من الأجزاء وCompose هي نفسها.
    • XML: يمكنك كتابة مضيف التنقل والرسم البياني مباشرةً بتنسيق XML.
    • أداة تعديل "استوديو Android": يمكنك استخدام أداة تعديل واجهة المستخدم الرسومية في "استوديو Android" لإنشاء الرسم البياني وتعديله كملف مورد XML.

إنشاء

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

@Serializable
object Profile
@Serializable
object FriendsList

val navController = rememberNavController()

NavHost(navController = navController, startDestination = Profile) {
    composable<Profile> { ProfileScreen( /* ... */ ) }
    composable<FriendsList> { FriendsListScreen( /* ... */ ) }
    // Add more destinations similarly.
}
  1. يمثل الكائن القابل للتسلسل كل مسار من المسارين، Profile وFriendsList.
  2. يؤدي الاستدعاء إلى عنصر NavHost القابل للإنشاء إلى تمرير NavController ومسار لوجهة البداية.
  3. في النهاية، تم تمرير دالة lambda إلى NavHost، وهي استدعاءات NavController.createGraph() وتعرض NavGraph.
  4. يتم توفير كل مسار كوسيطة نوع في NavGraphBuilder.composable<T>()، ما يؤدي إلى إضافة الوجهة إلى NavGraph الناتج.
  5. تعرض lambda التي تم تمريرها إلى composable ما يعرضه NavHost لهذه الوجهة.

فهم دالة lambda

لفهم دالة lambda التي تُنشئ NavGraph بشكلٍ أفضل، يمكنك إنشاء الرسم البياني نفسه كما في المقتطف السابق، ويمكنك إنشاء NavGraph بشكل منفصل باستخدام NavController.createGraph() وتمريره إلى NavHost مباشرةً:

val navGraph by remember(navController) {
  navController.createGraph(startDestination = Profile)) {
    composable<Profile> { ProfileScreen( /* ... */ ) }
    composable<FriendsList> { FriendsListScreen( /* ... */ ) }
  }
}
NavHost(navController, navGraph)

تمرير الوسيطات

إذا كنت بحاجة إلى تمرير البيانات إلى وجهة ما، فحدد المسار بفئة تتضمن معلمات. على سبيل المثال، المسار Profile هو فئة بيانات تحتوي على معلَمة name.

@Serializable
data class Profile(val name: String)

كلما احتجت إلى تمرير الوسيطات إلى هذه الوجهة، يمكنك إنشاء مثيل لفئة المسار، وتمرير الوسيطات إلى الدالة الإنشائية للفئة.

الحصول على مثيل المسار

يمكنك الحصول على مثيل المسار باستخدام NavBackStackEntry.toRoute() أو SavedStateHandle.toRoute(). عند إنشاء وجهة باستخدام composable()، تتوفّر السمة NavBackStackEntry كمَعلمة.

@Serializable
data class Profile(val name: String)

val navController = rememberNavController()

NavHost(navController = navController, startDestination = Profile(name="John Smith")) {
    composable<Profile> { backStackEntry ->
        val profile: Profile = backStackEntry.toRoute()
        ProfileScreen(name = profile.name) }
}

يُرجى مراعاة ما يلي في هذا المقتطف:

  • يحدّد مسار Profile وجهة البداية في الرسم البياني للتنقّل، مع إدراج "John Smith" كوسيطة في name.
  • والوجهة نفسها هي مجموعة composable<Profile>{}.
  • يأخذ العنصر ProfileScreen القابل للإنشاء القيمة profile.name كوسيطة name خاصة به.
  • ولذلك، تنتقل القيمة "John Smith" إلى ProfileScreen.

مثال بسيط

في ما يلي مثال كامل على نموذج عمل NavController وNavHost معًا:

@Serializable
data class Profile(val name: String)

@Serializable
object FriendsList

// Define the ProfileScreen composable.
@Composable
fun ProfileScreen(
    profile: Profile
    onNavigateToFriendsList: () -> Unit,
  ) {
  Text("Profile for ${profile.name}")
  Button(onClick = { onNavigateToFriendsList() }) {
    Text("Go to Friends List")
  }
}

// Define the FriendsListScreen composable.
@Composable
fun FriendsListScreen(onNavigateToProfile: () -> Unit) {
  Text("Friends List")
  Button(onClick = { onNavigateToProfile() }) {
    Text("Go to Profile")
  }
}

// Define the MyApp composable, including the `NavController` and `NavHost`.
@Composable
fun MyApp() {
  val navController = rememberNavController()
  NavHost(navController, startDestination = Profile(name = "John Smith")) {
    composable<Profile> { backStackEntry ->
        val profile: Profile = backStackEntry.toRoute()
        ProfileScreen(
            profile = profile,
            onNavigateToFriendsList = {
                navController.navigate(route = FriendsList)
            }
        )
    }
    composable<FriendsList> {
      FriendsListScreen(
        onNavigateToProfile = {
          navController.navigate(
            route = Profile(name = "Aisha Devi")
          )
        }
      )
    }
  }
}

كما يوضِّح المقتطف، بدلاً من تمرير NavController إلى العناصر القابلة للإنشاء، اعرض حدثًا على NavHost. وهذا يعني أنّه يجب أن تحتوي العناصر القابلة للإنشاء على معلَمة من النوع () -> Unit تجتاز لها NavHost دالة lambda التي تطلب NavController.navigate().

أجزاء

كما هو موضّح في الأقسام السابقة، عند استخدام الأجزاء، يمكنك إنشاء رسم بياني للتنقل آليًا باستخدام Kotlin DSL أو XML أو محرر Android Studio.

وتوضح الأقسام التالية بالتفصيل هذه الأساليب المختلفة.

آليًا

توفر لغة Kotlin DSL طريقة آلية لإنشاء رسم بياني للتنقل باستخدام الأجزاء. وهذا الأسلوب أكثر إتقانًا وحديثًا من استخدام ملف موارد XML.

يُرجى الاطّلاع على المثال التالي الذي يتيح استخدام رسم بياني للتنقّل على شاشتين.

أولاً، يجب إنشاء العنصر NavHostFragment الذي يجب ألا يتضمن عنصر app:navGraph:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

عليك بعد ذلك ضبط id من NavHostFragment على NavController.findNavController. يؤدي هذا إلى ربط NavController بـ NavHostFragment.

بعد ذلك، يربط الطلب NavController.createGraph() الرسم البياني بالسمة NavController، وبالتالي يؤدي أيضًا إلى NavHostFragment:

@Serializable
data class Profile(val name: String)

@Serializable
object FriendsList

// Retrieve the NavController.
val navController = findNavController(R.id.nav_host_fragment)

// Add the graph to the NavController with `createGraph()`.
navController.graph = navController.createGraph(
    startDestination = Profile(name = "John Smith")
) {
    // Associate each destination with one of the route constants.
    fragment<ProfileFragment, Profile> {
        label = "Profile"
    }

    fragment<FriendsListFragment, FriendsList>() {
        label = "Friends List"
    }

    // Add other fragment destinations similarly.
}

ويشبه استخدام DSL بهذه الطريقة إلى حد كبير سير العمل الموضّح في القسم السابق في Compose. على سبيل المثال، هنا وهنا، تنشئ الدالة NavController.createGraph() العنصر NavGraph. وبالمثل، تُضيف NavGraphBuilder.composable() وجهات قابلة للإنشاء إلى الرسم البياني، بينما تضيف NavGraphBuilder.fragment() هنا وجهة مجزّأة.

لمزيد من المعلومات حول كيفية استخدام Kotlin DSL، يمكنك الاطلاع على إنشاء رسم بياني باستخدام NavGraphBuilder DSL.

XML

يمكنك كتابة XML بنفسك مباشرةً. يتطابق المثال التالي مع مثال شاشتين من القسم السابق.

أولاً، عليك إنشاء NavHostFragment. هذا بمثابة مضيف التنقل الذي يحتوي على الرسم البياني للتنقل الفعلي.

الحد الأدنى من تنفيذ NavHostFragment:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:navGraph="@navigation/nav_graph" />

</FrameLayout>

يتضمّن NavHostFragment السمة app:navGraph. استخدم هذه السمة لربط الرسم البياني للتنقل بمضيف التنقل. إليك مثال على كيفية تنفيذ الرسم البياني:

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_graph"
    app:startDestination="@id/profile">

    <fragment
        android:id="@+id/profile"
        android:name="com.example.ProfileFragment"
        android:label="Profile">

        <!-- Action to navigate from Profile to Friends List. -->
        <action
            android:id="@+id/action_profile_to_friendslist"
            app:destination="@id/friendslist" />
    </fragment>

    <fragment
        android:id="@+id/friendslist"
        android:name="com.example.FriendsListFragment"
        android:label="Friends List" />

    <!-- Add other fragment destinations similarly. -->
</navigation>

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

أداة التعديل

يمكنك إدارة الرسم البياني للتنقّل في تطبيقك باستخدام "أداة تعديل التنقل" في "استوديو Android" وهذه في الأساس عبارة عن واجهة مستخدم تصويرية يمكنك استخدامها لإنشاء ملف XML الخاص بـ NavigationFragment وتعديله، كما هو موضّح في القسم السابق.

لمزيد من المعلومات، يُرجى الاطّلاع على محرر التنقل.

الرسوم البيانية المتداخلة

يمكنك أيضًا استخدام الرسوم البيانية المتداخلة. ويشمل ذلك استخدام رسم بياني كوجهة للتنقل. لمزيد من المعلومات، يُرجى الاطّلاع على الرسومات البيانية المضمَّنة.

قراءات إضافية

للتعرّف على مزيد من مفاهيم التنقّل الأساسية، يُرجى الاطّلاع على الأدلة التالية: