ناوبری و پشته قبلی‌ها

‫NavController «پشته قبلی‌ها» را نگه می‌دارد که حاوی مقصدهایی است که کاربر بازدید کرده است. وقتی کاربر در صفحه‌های مختلف برنامه شما پیمایش می‌کند، NavController مقصدها را به پشته قبلی‌ها اضافه و از آن حذف می‌کند.

پشته قبلی‌ها به‌عنوان یک پشته، ساختار داده‌ای «آخرین ورودی، اولین خروجی» است. بنابراین، NavController موارد را به بالای پشته فشار می‌دهد و از آنجا بیرون می‌کشد.

رفتار پایه

این‌ها حقایق اصلی‌ای هستند که باید درباره رفتار پشته قبلی‌ها درنظر بگیرید:

  • مقصد اول: وقتی کاربر برنامه را باز می‌کند، NavController مقصد اول را به بالای پشته قبلی‌ها می‌فرستد.
  • افزودن به پشته: هر تماس NavController.navigate() مقصد داده‌شده را به بالای پشته اضافه می‌کند.
  • بالا آوردن مقصد برتر: تک‌ضرب زدن روی بالا یا برگشت به‌ترتیب روش‌های NavController.navigateUp() و NavController.popBackStack() را فراخوانی می‌کند. مقصد بالایی را از پشته خارج می‌کنند. برای کسب اطلاعات بیشتر درباره تفاوت بین بالا و برگشت، به صفحه اصول پیمایش مراجعه کنید.

برگشتن

روش NavController.popBackStack() تلاش می‌کند مقصد فعلی را از پشته قبلی‌ها خارج کند و به مقصد قبلی پیمایش کند. این کار به‌طور مؤثری کاربر را یک مرحله در سابقه پیمایش او به عقب می‌برد. این تابع یک مقدار بولی برمی‌گرداند که نشان می‌دهد آیا بازگشت به مقصد با موفقیت انجام شده است یا نه.

برگشتن به مقصد خاصی

همچنین می‌توانید از popBackStack() برای پیمایش به مقصد خاصی استفاده کنید. برای انجام این کار، از یکی از اضافه‌بارهای آن استفاده کنید. چندین مورد وجود دارد که به شما امکان می‌دهد شناسه‌ای را ارسال کنید، مانند عدد صحیح id یا رشته route. این اضافه‌بارها کاربر را به مقصد مرتبط با شناسه ارائه‌شده می‌برند. نکته مهم این است که همه چیز را در پشته بالای آن مقصد قرار می‌دهند.

این اضافه‌بارها همچنین یک بولی inclusive می‌گیرند. این ویژگی تعیین می‌کند که آیا NavController باید مقصد مشخص‌شده را نیز پس‌از پیمایش به آن از پشته قبلی‌ها خارج کند یا نه.

برای نمونه، این قطعه کد کوتاه را درنظر بگیرید:

navController.popBackStack(R.id.destinationId, true)

در اینجا NavController با شناسه عدد صحیح destinationId به مقصد برمی‌گردد. چون مقدار آرگومان inclusive برابر با true است، NavController مقصد ارائه‌شده را نیز از پشته قبلی‌ها خارج می‌کند.

رسیدگی به بازگشت ناموفق به صفحه قبلی

وقتی popBackStack() مقدار false را برمی‌گرداند، تماس بعدی با NavController.getCurrentDestination() مقدار null را برمی‌گرداند. این یعنی برنامه آخرین مقصد را از پشته قبلی‌ها حذف کرده است. در این حالت، کاربر فقط صفحه‌ای خالی می‌بیند.

این اتفاق ممکن است در موارد زیر رخ دهد:

  • ‫popBackStack() چیزی را از پشته خارج نکرد.
  • popBackStack() مقصدی را از پشته قبلی‌ها خارج کرد و پشته اکنون خالی است.

برای حل این مشکل، باید به مقصد جدیدی پیمایش کنید یا با finish() تماس بگیرید تا فعالیت را پایان دهید. قطعه کد زیر این موضوع را نشان می‌دهد:

kotlin

...

if (!navController.popBackStack()) {
    // Call finish() on your Activity
    finish()
}

جاوا

...

if (!navController.popBackStack()) {
    // Call finish() on your Activity
    finish();
}

رفتن به مقصد

برای برداشتن مقصدها از پشته قبلی‌ها هنگام پیمایش از یک مقصد به مقصد دیگر، آرگومان popUpTo() را به فراخوانی تابع navigate() مربوطه اضافه کنید. popUpTo() به کتابخانه «پیمایش» دستور می‌دهد تا برخی‌از مقصدها را به‌عنوان بخشی از فراخوانی navigate() از پشته قبلی‌ها بردارد. مقدار پارامتر، شناسه مقصد در پشته قبلی‌ها است. شناسه می‌تواند عدد صحیح id یا رشته route باشد.

می‌توانید برای پارامتر inclusive آرگومانی با مقدار true اضافه کنید تا نشان دهید مقصدی که در popUpTo() مشخص کرده‌اید باید از پشته قبلی‌ها نیز حذف شود.

برای پیاده‌سازی این مورد به‌صورت برنامه‌نویسی، popUpTo() را به‌عنوان بخشی از NavOptions به navigate() منتقل کنید و inclusive را روی true تنظیم کنید. این ویژگی هم در Compose و هم در Views کار می‌کند.

ذخیره کردن وضعیت هنگام بالاپر شدن

وقتی از popUpTo برای پیمایش به مقصد استفاده می‌کنید، می‌توانید به‌صورت اختیاری پشته قبلی‌ها و وضعیت‌های همه مقصدهای خارج‌شده از پشته قبلی‌ها را ذخیره کنید. سپس می‌توانید هنگام پیمایش به آن مقصد در زمانی دیگر، پشته قبلی‌ها و مقصدها را بازیابی کنید. این کار به شما امکان می‌دهد وضعیت را برای مقصد مشخصی حفظ کنید و چند پشته قبلی‌ها داشته باشید.

برای انجام این کار به‌صورت برنامه‌نویسی، saveState = true را هنگام افزودن popUpTo به گزینه‌های پیمایش خود مشخص کنید.

همچنین می‌توانید restoreState = true را در گزینه‌های پیمایش خود مشخص کنید تا پشته قبلی‌ها و وضعیت مرتبط با مقصد را به‌طور خودکار بازیابی کنید.

برای مثال:

navController.navigate(
    route = route,
    navOptions =  navOptions {
        popUpTo<A>{ saveState = true }
        restoreState = true
    }
)

برای فعال کردن ذخیره و بازیابی وضعیت در XML، به‌ترتیب popUpToSaveState را به‌عنوان true و restoreState را به‌عنوان true در action مربوطه تعریف کنید.

نمونه Compose

در زیر نمونه کاملی از همان مورد در Compose ارائه شده است:

@Composable
fun MyAppNavHost(
    modifier: Modifier = Modifier,
    navController: NavHostController = rememberNavController(),
    startDestination: Any = A
) {
    NavHost(
        modifier = modifier,
        navController = navController,
        startDestination = startDestination
    ) {
        composable<A> {
            DestinationA(
                onNavigateToB = {
                // Pop everything up to, and including, the A destination off
                // the back stack, saving the back stack and the state of its
                // destinations.
                // Then restore any previous back stack state associated with
                // the B destination.
                // Finally navigate to the B destination.
                    navController.navigate(route = B) {
                        popUpTo<A> {
                            inclusive = true
                            saveState = true
                        }
                        restoreState = true
                    }
                },
            )
        }
        composable<B> { DestinationB(/* ... */) }
    }
}

@Composable
fun DestinationA(onNavigateToB: () -> Unit) {
    Button(onClick = onNavigateToB) {
        Text("Go to A")
    }
}

به‌طور دقیق‌تر، می‌توانید نحوه تماس با NavController.navigate() را به روش‌های زیر تغییر دهید:

// Pop everything up to the destination_a destination off the back stack before
// navigating to the "destination_b" destination
navController.navigate("destination_b") {
    popUpTo("destination_a")
}

// Pop everything up to and including the "destination_a" destination off
// the back stack before navigating to the "destination_b" destination
navController.navigate("destination_b") {
    popUpTo("destination_a") { inclusive = true }
}

// Navigate to the "search” destination only if we’re not already on
// the "search" destination, avoiding multiple copies on the top of the
// back stack
navController.navigate("search") {
    launchSingleTop = true
}

برای اطلاعات کلی درباره ارسال گزینه‌ها به NavController.navigate()، راهنمای پیمایش با گزینه‌ها را ببینید.

نمونه XML

در اینجا نمونه‌ای از popUpTo در XML بااستفاده از کنش آورده شده است:

<action
  android:id="@+id/action_a_to_b"
  app:destination="@id/b"
  app:popUpTo="@+id/a"
  app:popUpToInclusive="true"
  app:restoreState=”true”
  app:popUpToSaveState="true"/>

ترکاندن بااستفاده از کنش‌ها

هنگام پیمایش بااستفاده از کنش، می‌توانید به‌طور اختیاری مقصدهای بیشتری را از پشته قبلی‌ها حذف کنید. برای مثال، اگر برنامه‌تان جریان ورود به سیستم اولیه دارد، وقتی کاربر به سیستم وارد شد، باید همه مقصدهای مربوط به ورود به سیستم را از پشته قبلی‌ها خارج کنید تا دکمه «برگشت» کاربران را به جریان ورود به سیستم برنگرداند.

مطالب خواندنی بیشتر

برای اطلاعات بیشتر، صفحه‌های زیر را بخوانید:

  • پیمایش دایره‌ای: با نحوه جلوگیری از پشته قبلی‌های بیش‌ازحد پرشده در مواردی که جریان‌های پیمایش دایره‌ای هستند آشنا شوید.
  • مقصدهای کادر گفتگو: درباره اینکه چگونه مقصدهای کادر گفتگو ملاحظات منحصربه‌فردی را برای نحوه مدیریت پشته قبلی‌ها معرفی می‌کنند بخوانید.