ناوبری، نحوه حرکت کاربران در برنامه شما را توصیف میکند. کاربران معمولاً با ضربه زدن یا کلیک کردن روی عناصر رابط کاربری، با آنها تعامل دارند و برنامه با نمایش محتوای جدید پاسخ میدهد. اگر کاربر بخواهد به محتوای قبلی برگردد، از ژست برگشت یا ضربه زدن روی دکمه برگشت استفاده میکند.
مدلسازی وضعیت ناوبری
یک روش مناسب برای مدلسازی این رفتار، استفاده از پشتهای از محتوا است. وقتی کاربر به سمت محتوای جدید حرکت میکند، آن محتوا به بالای پشته منتقل میشود. وقتی از آن محتوا برمیگردد ، از پشته خارج شده و محتوای قبلی نمایش داده میشود. در اصطلاحات ناوبری، این پشته معمولاً به عنوان پشته پشتی شناخته میشود زیرا نشاندهنده محتوایی است که کاربر میتواند به آن برگردد .

یک پشته ایجاد کنید
در ناوبری ۳، پشته پشتی در واقع حاوی محتوا نیست. در عوض، حاوی ارجاعاتی به محتوا است که به عنوان کلید شناخته میشوند. کلیدها میتوانند از هر نوعی باشند اما معمولاً کلاسهای داده ساده و قابل سریالسازی هستند. استفاده از ارجاعات به جای محتوا مزایای زیر را دارد:
- با فشار دادن کلیدها روی پشته پشتی، پیمایش آسان است.
- تا زمانی که کلیدها قابل سریالسازی باشند، میتوان back stack را در حافظه دائمی ذخیره کرد و به آن اجازه داد تا از تغییرات پیکربندی و مرگ فرآیند جان سالم به در ببرد. این مهم است زیرا کاربران انتظار دارند برنامه شما را ترک کنند، بعداً به آن برگردند و با همان محتوایی که نمایش داده میشود، از جایی که متوقف شدهاند، ادامه دهند. برای اطلاعات بیشتر به Save your back stack مراجعه کنید.
یک مفهوم کلیدی در API ناوبری ۳ این است که شما مالک پشته (back stack) هستید. این کتابخانه:
- انتظار میرود که پشته پشتی شما یک
List<T>با وضعیت snapshot باشد، که در آنTنوعkeysپشته پشتی شما است. میتوانیدAnyاستفاده کنید یا کلیدهای خود را با نوع قویتر ارائه دهید. وقتی اصطلاحات "push" یا "pop" را میبینید، پیادهسازی اساسی آن اضافه کردن یا حذف کردن موارد از انتهای یک لیست است. - پشته (stack) شما را مشاهده میکند و وضعیت آن را با استفاده از
NavDisplayدر رابط کاربری (UI) منعکس میکند.
مثال زیر نحوه ایجاد کلیدها و یک پشته پشتی و تغییر پشته پشتی در پاسخ به رویدادهای ناوبری کاربر را نشان میدهد:
// Define keys that will identify content data object ProductList data class ProductDetail(val id: String) @Composable fun MyApp() { // Create a back stack, specifying the key the app should start with val backStack = remember { mutableStateListOf<Any>(ProductList) } // Supply your back stack to a NavDisplay so it can reflect changes in the UI // ...more on this below... // Push a key onto the back stack (navigate forward), the navigation library will reflect the change in state backStack.add(ProductDetail(id = "ABC")) // Pop a key off the back stack (navigate back), the navigation library will reflect the change in state backStack.removeLastOrNull() }
حل کلیدهای محتوا
محتوا در Navigation 3 با استفاده از NavEntry مدلسازی میشود، که کلاسی شامل یک تابع قابل ترکیب است. این کلاس یک مقصد را نشان میدهد - یک قطعه واحد از محتوا که کاربر میتواند به جلو و عقب حرکت کند.
یک NavEntry همچنین میتواند شامل فراداده - اطلاعاتی در مورد محتوا - باشد. این فرادادهها میتوانند توسط اشیاء نگهدارنده، مانند NavDisplay ، خوانده شوند تا به آنها در تصمیمگیری در مورد نحوه نمایش محتوای NavEntry کمک کنند. به عنوان مثال، فرادادهها میتوانند برای لغو انیمیشنهای پیشفرض برای یک NavEntry خاص استفاده شوند. metadata NavEntry نقشهای از کلیدهای String به مقادیر Any است که امکان ذخیرهسازی دادههای متنوع را فراهم میکند.
برای تبدیل یک key به NavEntry ، یک Entry Provider ایجاد کنید. این تابعی است که یک key میپذیرد و یک NavEntry برای آن key برمیگرداند. معمولاً هنگام ایجاد NavDisplay به عنوان یک پارامتر لامبدا تعریف میشود.
دو راه برای ایجاد یک Entry Provider وجود دارد، یا با ایجاد مستقیم یک تابع لامبدا، یا با استفاده از entryProvider DSL.
مستقیماً یک تابع Entry Provider ایجاد کنید
شما معمولاً با استفاده از دستور when یک تابع Entry Provider ایجاد میکنید که برای هر یک از کلیدهای شما یک شاخه دارد.
entryProvider = { key -> when (key) { is ProductList -> NavEntry(key) { Text("Product List") } is ProductDetail -> NavEntry( key, metadata = mapOf("extraDataKey" to "extraDataValue") ) { Text("Product ${key.id} ") } else -> { NavEntry(Unit) { Text(text = "Invalid Key: $it") } } } }
از entryProvider DSL استفاده کنید
DSL entryProvider میتواند با اجتناب از نیاز به آزمایش روی هر یک از انواع کلید شما و ساخت یک NavEntry برای هر کدام، تابع lambda شما را ساده کند. برای این کار از تابع سازنده entryProvider استفاده کنید. همچنین شامل رفتار پیشفرض fallback (ارسال خطا) در صورت عدم یافتن کلید است.
entryProvider = entryProvider { entry<ProductList> { Text("Product List") } entry<ProductDetail>( metadata = mapOf("extraDataKey" to "extraDataValue") ) { key -> Text("Product ${key.id} ") } }
به موارد زیر از قطعه کد توجه کنید:
-
entryبرای تعریف یکNavEntryبا نوع داده شده و محتوای قابل ترکیب استفاده میشود. -
entryیک پارامترmetadataبرای تنظیمNavEntry.metadataمیپذیرد.
پشته را نمایش دهید
پشته پشتی نشاندهنده وضعیت ناوبری برنامه شماست. هر زمان که پشته پشتی تغییر کند، رابط کاربری برنامه باید وضعیت جدید پشته پشتی را منعکس کند. در ناوبری ۳، یک NavDisplay پشته پشتی شما را مشاهده میکند و رابط کاربری خود را بر اساس آن بهروزرسانی میکند. آن را با پارامترهای زیر بسازید:
- پشته پشتی شما - این باید از نوع
SnapshotStateList<T>باشد، که در آنTنوع کلیدهای پشته پشتی شما است. این یکListقابل مشاهده است به طوری که هنگام تغییر، ترکیبNavDisplayرا فعال میکند. - یک
entryProviderبرای تبدیل کلیدهای موجود در back stack شما به اشیاءNavEntry. - به صورت اختیاری، یک لامبدا به پارامتر
onBackبدهید. این زمانی فراخوانی میشود که کاربر یک رویداد back را فعال کند.
مثال زیر نحوه ایجاد یک NavDisplay را نشان میدهد.
data object Home data class Product(val id: String) @Composable fun NavExample() { val backStack = remember { mutableStateListOf<Any>(Home) } NavDisplay( backStack = backStack, onBack = { backStack.removeLastOrNull() }, entryProvider = { key -> when (key) { is Home -> NavEntry(key) { ContentGreen("Welcome to Nav3") { Button(onClick = { backStack.add(Product("123")) }) { Text("Click to navigate") } } } is Product -> NavEntry(key) { ContentBlue("Product ${key.id} ") } else -> NavEntry(Unit) { Text("Unknown route") } } } ) }
به طور پیشفرض، NavDisplay بالاترین NavEntry در پشته پشتی در یک طرح تکصفحهای نشان میدهد. ضبط زیر این برنامه را در حال اجرا نشان میدهد:

NavDisplay با دو مقصد.چرخه حیات مقصد
NavDisplay از LifecycleOwner سفارشی برای محدود کردن وضعیت چرخه عمر یک NavEntry بر اساس محدودیتهای سطح Scene و محدودیتهای سطح Entry استفاده میکند.
برای اطلاعات بیشتر در مورد چرخههای حیات در Compose، به Lifecycle در Jetpack Compose مراجعه کنید.
محدودیتهای چرخه حیات در سطح صحنه
NavDisplay چرخه حیات Scene فعال را مدیریت میکند. محدودیتهای سطح صحنه به شرح زیر تعیین میشوند:
برای صحنههای بدون همپوشانی:
-
RESUMED: فقط زمانی مجاز است که انتقال صحنه به حالت عادی برگشته باشد و هیچ صحنهی همپوشانی فعالی روی آن نمایش داده نشود. -
STARTED): در حین انتقال صحنه، مانند هنگام حرکت به جلو یا عقب، یا زمانی که با یک پوشش پوشانده شده است، رویSTARTEDمحدود میشود.
برای صحنههای روی هم افتاده ، مانند دیالوگها یا صفحات پایینی:
-
RESUMED: فقط برای بالاترین صحنهی همپوشانی فعال فعلی مجاز است. -
STARTED: برای هر صحنهی پوششی زیرین که توسط یک پوشش جدیدتر پوشانده شده است، باSTARTEDمحدود میشود.
وضعیت چرخه حیات سطح ورودی
این کتابخانه حداکثر وضعیت چرخه حیات هر NavEntry را بر اساس حضور آن در back stack مدیریت میکند:
-
RESUMED: اگر ورودی در پشته فعلی موجود باشد، چرخه حیات آن مجاز است تاRESUMED(با توجه به محدودیت سطح صحنه) ادامه یابد. -
CREATED): اگر ورودی دیگر در پشته پشتی نباشد ، مانند زمانی که ظاهر شده اما هنوز در حین انیمیشنسازی روی صفحه نمایش داده میشود، کتابخانه چرخه حیات آن را به شدت درCREATEDمحدود میکند. این محدودیت تضمین میکند که ورودیهای پسزمینه یا در حال خروج، اجرای کارهای فعال مانند جمعآوری جریانها یا راهاندازی کوروتینهای محدود به حالتهایRESUMEDیاSTARTEDرا در حین اتمام انتقالهای خروج خود متوقف میکنند.
چگونه ترکیب میشوند
برای مثال، وضعیت نهایی چرخه حیات یک NavEntry به صورت زیر حل میشود:
| سناریو | محدودیت سطح صحنه | سقف سطح مبتدی | درپوش مؤثر |
|---|---|---|---|
| ورود فعال، صفحه ثابت (بدون انتقال یا همپوشانی) | RESUMED | RESUMED | RESUMED |
| ورود فعال، در حین انتقال (رفتن به یا از) | STARTED | RESUMED | STARTED |
| ورودی فعال، پوشیده شده توسط یک پوشش (برای مثال، یک پنجره گفتگو باز است) | STARTED | RESUMED | STARTED |
| ورودی ظاهر شده، متحرک سازی شده | STARTED یا RESUMED | CREATED | CREATED |
همه چیز را کنار هم قرار دادن
نمودار زیر نحوهی جریان دادهها بین اشیاء مختلف در Navigation 3 را نشان میدهد:

رویدادهای ناوبری تغییرات را آغاز میکنند . کلیدها در پاسخ به تعاملات کاربر به back stack اضافه یا حذف میشوند.
تغییر در وضعیت پشته پشتی، بازیابی محتوا را آغاز میکند .
NavDisplay(یک کامپوننت که یک پشته پشتی را رندر میکند) پشته پشتی را مشاهده میکند. در پیکربندی پیشفرض، بالاترین ورودی پشته پشتی را در یک طرحبندی تکصفحهای نمایش میدهد. هنگامی که کلید بالایی در پشته پشتی تغییر میکند،NavDisplayاز این کلید برای درخواست محتوای مربوطه از ارائهدهنده ورودی استفاده میکند.ارائهدهنده ورودی، محتوا را فراهم میکند . ارائهدهنده ورودی تابعی است که یک کلید را به
NavEntryتبدیل میکند. پس از دریافت یک کلید ازNavDisplay، ارائهدهنده ورودی،NavEntryمرتبط را ارائه میدهد که شامل کلید و محتوا است.محتوا نمایش داده میشود .
NavDisplayNavEntryرا دریافت کرده و محتوا را نمایش میدهد.