NavHost — چیست، ساخت گراف و مسیرها در Jetpack Compose

نویسنده: IT Sectr منتشر شده: 2026-06-30 زمان مطالعه: 7 دقیقه

NavHost یک کانتینر composable است که به عنوان نقطه ورود برای گراف ناوبری در Jetpack Compose عمل می‌کند. این کامپوننت NavController را به مجموعه‌ای از مسیرها متصل می‌کند و صفحه فعلی را بر اساس وضعیت back stack نمایش می‌دهد. بر اساس Android Developers (2025)، NavHost یک کامپوننت اجباری برای هر برنامه Compose با ناوبری است. در داخل NavHost، مسیرهای composable با آرگومان‌های اختیاری، deep links و انیمیشن ثبت می‌شوند. هر مسیر یک تابع composable معمولی است که NavBackStackEntry با داده‌های انتقال دریافت می‌کند. NavHost به طور خودکار back press، ذخیره وضعیت و بازیابی در بازپیکربندی را مدیریت می‌کند.

نکات اصلی

  • NavHost — کانتینر composable که NavController را به گراف مسیرها متصل کرده و صفحه فعلی را نمایش می‌دهد
  • composable() — تابع ثبت مسیر با route، آرگومان‌ها، deep links و انیمیشن انتقال
  • startDestination — مسیر اولیه‌ای که هنگام ایجاد NavHost باز می‌شود
  • آرگومان‌ها از طریق navArgument با NavType برای انتقال تایپ‌شده داده بین صفحه‌ها تعریف می‌شوند
  • انیمیشن به صورت سراسری یا فردی از طریق پارامترهای enterTransition، exitTransition پیکربندی می‌شود

NavHost در Jetpack Compose چیست؟

NavHost یک تابع composable است که کانتینری برای نمایش صفحه ناوبری فعلی فراهم می‌کند. NavHost یک NavController، startDestination و گراف مسیرهای ساخته شده از طریق Kotlin DSL را می‌پذیرد. هنگام تغییر مسیر فعلی، NavHost composable نمایش داده شده را با انیمیشن مشخص شده تغییر می‌دهد.

NavHost مانند یک تغییردهنده صفحه کار می‌کند: NavBackStackEntry فعلی را از NavController ردیابی کرده و بلوک composable مربوطه را نمایش می‌دهد. هر صفحه یک تابع composable مستقل است که NavBackStackEntry را با آرگومان‌های مسیر دریافت می‌کند. همه صفحه‌ها در یک درخت ترکیب واحد وجود دارند، اما NavHost فقط یکی را در یک زمان نشان می‌دهد و بقیه را از طریق انیمیشن پنهان می‌کند.

برخلاف FragmentManager، NavHost برای هر صفحه Fragment ایجاد نمی‌کند. تمام چرخه حیات از طریق CompositionLifecycle مدیریت می‌شود — توابع composable دارای onStart/onResume نیستند، بنابراین برای عوارض جانبی از LaunchedEffect و DisposableEffect استفاده می‌شود. NavHost به طور خودکار در NavController مشترک شده و UI را هنگام تغییر مسیر بازترکیب می‌کند.

بر اساس Google، NavHost از نسخه Navigation 2.4.0 یک API پایدار است. از نسخه 2.8.0، NavHost از Type-Safe Navigation از طریق Kotlin Serialization پشتیبانی می‌کند که routeهای رشته‌ای را با data-کلاس‌ها جایگزین می‌کند. NavHost همچنین از گراف‌های تودرتو پشتیبانی می‌کند که امکان سازماندهی ناوبری بر اساس ماژول‌ها را فراهم می‌کند.

NavHost با دو پارامتر اجباری ایجاد می‌شود: navController (نمونه NavHostController) و startDestination (رشته مسیر صفحه اول). پارامتر سوم — بلوک builder است که در آن همه مسیرها از طریق composable()، navigation() و dialog() ثبت می‌شوند.

kotlin
@Composable
fun AppNavHost(navController: NavHostController) {
    NavHost(
        navController = navController,
        startDestination = "home"
    ) {
        composable("home") { HomeScreen(navController) }
        composable("settings") { SettingsScreen(navController) }
    }
}

startDestination مسیری است که هنگام راه‌اندازی اولیه NavHost باز می‌شود. اگر back stack خالی باشد، NavHost به طور خودکار startDestination را به پشته اضافه می‌کند. در بازپیکربندی (چرخش صفحه)، NavHost آخرین مسیر را از savedState بازیابی می‌کند، نه startDestination.

برای BottomNavigation، startDestination یکی از مسیرهای پنل پایینی است. سایر مسیرهای پنل به عنوان ورودی‌های composable جداگانه اضافه می‌شوند. NavHost باید در داخل Scaffold.content قرار گیرد — جایی که محتوای اصلی برنامه نمایش داده می‌شود. NavHost تمام ارتفاع موجود پس از کسر TopAppBar و BottomNavigation را اشغال می‌کند.

ثبت مسیرها از طریق composable

تابع composable(route, arguments, deepLinks, enterTransition, exitTransition, content) یک مسیر را در گراف NavHost ثبت می‌کند. پارامتر route رشته‌ای است که مسیر را با placeholderهای اختیاری به فرم {paramName} توصیف می‌کند. placeholder هنگام ناوبری با مقدار مشخص جایگزین می‌شود.

بلوک content NavBackStackEntry دریافت می‌کند که آرگومان‌ها از آن استخراج می‌شوند. تابع composable صفحه فقط زمانی نمایش داده می‌شود که مسیر فعلی NavController با route مطابقت داشته باشد. در صورت عدم تطابق، composable از ترکیب حذف می‌شود، اما وضعیت آن می‌تواند از طریق rememberSaveable یا ViewModel با SavedStateHandle حفظ شود.

kotlin
composable(
    route = "article/{articleId}",
    arguments = listOf(navArgument("articleId") {
        type = NavType.IntType
        defaultValue = 0
    }),
    deepLinks = listOf(navDeepLink { uriPattern = "https://app.example/article/{articleId}" })
) { backStackEntry ->
    val articleId = backStackEntry.arguments?.getInt("articleId") ?: 0
    ArticleScreen(articleId = articleId)
}

تعداد ورودی‌های composable در داخل NavHost می‌تواند هر چیزی باشد — از چند تا صدها. برای برنامه‌های بزرگ، مسیرها بر اساس ماژول‌ها تقسیم و از طریق گراف‌های تودرتو متصل می‌شوند. هر composable می‌تواند تنظیمات انیمیشن، deep links و آرگومان‌های خاص خود را داشته باشد.

آرگومان‌ها و پارامترهای تایپ‌شده مسیرها

آرگومان‌های مسیر از طریق پارامتر arguments: List<NamedNavArgument> در composable() تعریف می‌شوند. هر آرگومان از طریق navArgument(name) { type; defaultValue } مشخص می‌شود. NavType نوع آرگومان را تعیین می‌کند: StringType، IntType، LongType، FloatType، BoolType، ParcelableType و ReferenceType.

پارامتر مسیرمثال routeNavType
مسیر (path)«user/{id}»NavType.IntType
پرس و جو (query)«search?q={query}»NavType.StringType
اختیاری«details/{id}?tab={tab}»StringType + defaultValue=«»
Parcelable«checkout/{order}»NavType.ParcelableType

آرگومان‌ها از NavBackStackEntry از طریق arguments?.getInt("id") استخراج می‌شوند. برای آرگومان‌های اجباری، defaultValue می‌تواند حذف شود — NavType از null استفاده خواهد کرد. برای آرگومان‌های اختیاری، defaultValue اجباری است، در غیر این صورت ناوبری در صورت عدم وجود پارامتر استثنا ایجاد می‌کند.

از نسخه Navigation 2.8.0، Type-Safe Navigation توصیه می‌شود: یک sealed class یا data class برای مسیرها با Kotlin Serialization تعریف کنید. به جای route رشته‌ای از composable<RouteType> { backStackEntry -> } استفاده کنید. این کار اشتباهات تایپی در route را حذف کرده و به طور خودکار NavType را برای آرگومان‌ها تولید می‌کند. برای مهاجرت، وابستگی navigation-compose-typesafe و پلاگین Kotlin Serialization را اضافه کنید.

گراف‌های تودرتو ناوبری

nested graphs — مکانیزم گروه‌بندی مسیرها در داخل NavHost از طریق تابع navigation(route, startDestination) است. یک گراف تودرتو پیشوند route و startDestination خاص خود را دارد و همه مسیرهای آن از طریق پیشوند در دسترس هستند. nested graphs برای معماری ماژولار استفاده می‌شوند، جایی که هر ماژول ویژگی زیرگراف خود را ثبت می‌کند.

مزایای گراف‌های تودرتو: ایزوله‌سازی مسیرها در داخل ماژول، back stack واحد برای گروهی از صفحه‌ها، امکان ناوبری با پیشوند بدون افشای ساختار داخلی. به عنوان مثال، گراف «auth» شامل «auth/login» و «auth/register» است. ناوبری هم از طریق مسیر کامل و هم از طریق پیشوند با تغییرمسیر به startDestination امکان‌پذیر است.

kotlin
NavHost(navController = navController, startDestination = "main") {
    composable("main") { MainScreen(navController) }
    navigation(
        route = "auth",
        startDestination = "auth/login"
    ) {
        composable("auth/login") { LoginScreen(navController) }
        composable("auth/register") { RegisterScreen(navController) }
    }
}

nested graphs از انتقال آرگومان‌ها در سطح گراف پشتیبانی می‌کند: پارامترهای اعلام‌شده در route گراف به همه مسیرهای داخلی منتقل می‌شوند. برای پاک کردن گراف تودرتو از popBackStack(route) استفاده کنید — همه ورودی‌های داخلی را حذف می‌کند. گراف‌های تودرتو محدودیت عمق ندارند، اما برای خوانایی بیش از ۳ سطح توصیه نمی‌شود.

انیمیشن و سفارشی‌سازی انتقال

NavHost از انیمیشن انتقال بین مسیرهای composable از طریق پارامترهای enterTransition، exitTransition، popEnterTransition و popExitTransition پشتیبانی می‌کند. انیمیشن‌ها یک بار برای NavHost تعریف شده و برای همه مسیرها اعمال می‌شوند، یا به صورت فردی برای هر composable. به طور پیش‌فرض انیمیشن غیرفعال است.

پیکربندی معمول: enterTransition = slideInHorizontally(initialOffsetX = { it }) — صفحه از راست وارد می‌شود؛ exitTransition = slideOutHorizontally(targetOffsetX = { -it }) — صفحه به چپ خارج می‌شود. برای انیمیشن pop جهت‌ها معکوس هستند: صفحه از چپ وارد و به راست خارج می‌شود. برای BottomNavigation از fadeIn/fadeOut بدون slide استفاده می‌شود.

kotlin
NavHost(
    navController = navController,
    startDestination = "home",
    enterTransition = { slideInHorizontally(initialOffsetX = { it }) + fadeIn() },
    exitTransition = { slideOutHorizontally(targetOffsetX = { -it }) + fadeOut() },
    popEnterTransition = { slideInHorizontally(initialOffsetX = { -it }) + fadeIn() },
    popExitTransition = { slideOutHorizontally(targetOffsetX = { it }) + fadeOut() }
) { /* composable routes */ }

انیمیشن‌های سفارشی از طریق Compose Animation API ایجاد می‌شوند: AnimatedContentTransitionScope دسترسی به اندازه‌های کانتینر، پیشرفت انیمیشن و direction را فراهم می‌کند. برای shared element transition (یک element به آرامی به صفحه دیگر منتقل می‌شود) به کتابخانه Accompanist Navigation Animation یا پیاده‌سازی سفارشی از طریق sharedElement Modifier نیاز است. بر اساس Android Developers (2025)، انیمیشن slide پیش‌فرض (ورود از راست، خروج به چپ) در ۸۰٪ از برنامه‌های Android با ناوبری استفاده می‌شود.

سوالات متداول

آیا می‌توان از چند NavHost در یک Activity استفاده کرد؟

از نظر فنی بله، اما توصیه نمی‌شود. هر NavHost یک back stack مستقل ایجاد می‌کند که ناوبری یکپارچه را مختل می‌کند. استثنا — مناطق جداگانه، مانند NavHost برای محتوای اصلی و NavHost برای BottomSheet با ناوبری خاص خود.

تفاوت NavHost و Scaffold در Compose چیست؟

NavHost — کانتینر ناوبری که صفحه‌ها را تغییر می‌دهد. Scaffold — طرح‌بندی کل صفحه (TopAppBar، BottomNavigation، FloatingActionButton). معمولاً NavHost در داخل Scaffold.content قرار می‌گیرد. Scaffold ناوبری را مدیریت نمی‌کند، بلکه فقط slotهایی برای کامپوننت‌های UI فراهم می‌کند.

چگونه ViewModel را بین صفحه‌ها از طریق NavHost منتقل کنیم؟

ViewModel در چارچوب NavBackStackEntry از طریق viewModel() ایجاد می‌شود. برای به اشتراک‌گذاری ViewModel بین صفحه‌ها از parentNavController استفاده کنید: ViewModel مشترک را به entry والد متصل کنید. جایگزین — DI (Hilt/Koin) با scope روی NavGraph.

چرا NavHost composable را در هر انتقال بازآفرینی می‌کند؟

این رفتار عادی است — NavHost composable را هنگام خروج از مسیر از ترکیب حذف می‌کند. برای حفظ وضعیت از rememberSaveable برای وضعیت UI و ViewModel با SavedStateHandle برای منطق تجاری استفاده کنید.

چگونه مدیریت ۴۰۴ (مسیر ناشناخته) را در NavHost اضافه کنیم؟

آخرین مسیر composable("404") را اضافه کنید و در صورت deep link ناشناخته به آن ناوبری کنید. NavHost مسیر catch-all ندارد — مسیر را در intent-handler Deep Link قبل از navigate() بررسی کنید. اگر route پیدا نشد — به ۴۰۴ navigate کنید.

خلاصه

  • NavHost — کانتینر composable Navigation Compose که NavController را به گراف مسیرها متصل کرده و صفحه فعلی را نمایش می‌دهد
  • composable() مسیر را با route، آرگومان‌ها (NavType)، deep links و انیمیشن ثبت می‌کند
  • startDestination — مسیر اولیه‌ای که هنگام اولین راه‌اندازی NavHost باز می‌شود
  • آرگومان‌ها از طریق placeholderهای {param} با NavType برای تایپ‌سازی و defaultValue برای پارامترهای اختیاری منتقل می‌شوند
  • گراف‌های تودرتو از طریق navigation() امکان گروه‌بندی مسیرها بر اساس ماژول‌ها با back stack ایزوله را فراهم می‌کند
  • انیمیشن انتقال از طریق enterTransition/exitTransition با استفاده از Compose Animation API پیکربندی می‌شود
  • NavHost به طور خودکار back press، ذخیره وضعیت و deep links را بدون کد اضافی مدیریت می‌کند

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید