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

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

أنواع الوجهات

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

النوع

الوصف

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

مستضافة

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

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

مربّع حوار

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

التنبيهات والاختيارات والنماذج

النشاط

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

أن تكون بمثابة نقطة خروج من الرسم البياني للتنقّل الذي يشغّل نشاط 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، استخدِم كائنًا أو فئة قابلة للتسلسل لتحديد مسار. يصف المسار كيفية الوصول إلى وجهة معيّنة، ويحتوي على جميع المعلومات التي تتطلّبها الوجهة.

استخدِم التعليق التوضيحي @Serializable لإنشاء طريَق برمجية ضرورية لتحويل البيانات إلى سلسلة وتحويلها من سلسلة لأنواع المسارات تلقائيًا. يتم توفير هذا التعليق التوضيحي من خلال مكوّن Kotlin Serialization الإضافي. اتّبِع هذه التعليمات لإضافة هذا المكوّن الإضافي.

بعد تحديد مساراتك، استخدِم العنصر القابل للتجميع 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)

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

بالنسبة إلى الوسيطات الاختيارية، أنشئ حقولًا يمكن أن تحتوي على قيمة فارغة مع قيمة تلقائية.

@Serializable
data class Profile(val nickname: String? = null)

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

يمكنك الحصول على مثيل المسار باستخدام 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 الوجهة الأساسية في gráph التنقّل، مع استخدام "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 بهذه الطريقة سير العمل الموضّح في القسم السابق عن الإنشاء. على سبيل المثال، في كل من هنا وهناك، تنشئ الدالة NavController.createGraph() القيمة NavGraph. وبالمثل، بينما تُضيف NavGraphBuilder.composable() وجهات قابلة للتجميع إلى الرسم البياني، تُضيف NavGraphBuilder.fragment() هنا وجهة للفقرة.

لمزيد من المعلومات عن كيفية استخدام Kotlin DSL، اطّلِع على مقالة إنشاء رسم بياني باستخدام لغة برمجة مختصرة NavGraphBuilder.

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. لمزيد من المعلومات، اطّلِع على استخدام إجراءات التنقّل والمقتطفات.

محرِّر

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

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

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

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

مراجع إضافية

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