Navigation در کامپوز Jetpack Compose


سلام خدمت دوستان برنامه نویس ام ، در این مقاله میخوایم بررسی کنیم که Navigation در کامپوز به چه صورت است و چطوری استفاده کنیم ، این ابزار به شما کمک میکنه تا راحت و حرفهای ناوبری (Navigation) بین صفحات یا همون کامپوزبلهاتون رو مدیریت کنین.
سلام خدمت دوستان برنامه نویس ام ، در این مقاله میخوایم بررسی کنیم که Navigation در کامپوز به چه صورت است و چطوری استفاده کنیم ، این ابزار به شما کمک میکنه تا راحت و حرفهای ناوبری (Navigation) بین صفحات یا همون کامپوزبلهاتون رو مدیریت کنین.
اگه قبلاً با Navigation Component در روش سنتی اندروید (با XML و Viewها) آشنا بودین، احتمالاً اینجا هم سریع راه میفتین. ولی خبر خوب اینه که دیگه خبری از XML نیست و همه چی توی همون کاتلین خلاصه شده! 😎
در ابتدای کار ، من بخش های مهم این نویگشین رو معرفی میکنم ، در پایان یه مثال کلی میزنم که مطلب جا بی افته !
بخش اول: تغییرات اصلی در Navigation Component
حذف فایلهای XML
یادتونه که توی روش سنتی برای مدیریت نویگیشن باید یه فایل XML برای تعریف Navigation Graph میساختیم؟ خب، حالا دیگه نیازی به اون نیست. توی Jetpack Compose همهی این کارها توی کد کاتلین انجام میشه.
شباهتها با روش سنتی
بعضی چیزا تغییر نکردن، مثل:
- استفاده از NavController برای مدیریت ناوبری.
- نیاز به NavHost و تعریف مقصدها (Destinations).
- ارسال داده بین صفحات با آرگومانها.
محدودیتهای جدید
یه نکته مهم اینه که توی Compose توصیه شده اشیاء کامل (Objects) رو بین صفحات نفرستین. فقط مقادیر ساده مثل String
یا Int
رو ارسال کنین. اگه نیاز به ارسال دادههای پیچیدهتر دارین، بهتره شناسه (ID) اون داده رو بفرستین و توی مقصد، داده کامل رو از دیتابیس یا یه منبع دیگه بگیرین.
بخش دوم: استفاده از NavController
اضافه کردن کتابخونه نویگیشن
اول از همه باید کتابخونه مورد نیاز رو اضافه کنیم. مطمئن بشید آخرین نسخه رو توی فایل build.gradle
اضافه کردین:
dependencies { implementation "androidx.navigation:navigation-compose:2.8.4" }
ایجاد NavController
برای مدیریت ناوبری، باید یه NavController داشته باشیم. این کار رو با تابع rememberNavController
انجام میدیم. مثلاً:
val navController = rememberNavController()
این navController
رو باید به همهی کامپوزبلهایی که نیاز به ناوبری دارن، برسونیم.
اتصال NavController به NavHost
نوهاست NavHost که مقصدها (Destinations) و مسیرها (Routes) رو تعریف میکنیم. همچنین باید یه صفحهی شروع (Start Destination) هم مشخص کنیم:
NavHost( navController = navController, startDestination = "home" ) { composable("home") { HomeScreen(navController) } composable("details") { DetailsScreen(navController) } }
بخش سوم: تعریف مقصدها و مسیریابی
تعریف مقصدها (Destinations)
هر صفحه یا کامپوزبل یه مقصد محسوب میشه. مقصدها رو با استفاده از تابع composable
توی NavHost
تعریف میکنیم. هر مقصد باید یه مسیر (Route) داشته باشه:
composable("home") { HomeScreen(navController) } composable("details") { DetailsScreen(navController) }
مسیریابی بین مقصدها
برای ناوبری به یه مقصد دیگه، از تابع navigate
در NavController
استفاده میکنیم. مثلاً:
Button(onClick = { navController.navigate("details") }) { Text("Go to Details") }
نکته مهم: تابع
navigate
رو فقط تویonClick
یا Callbackها صدا بزنین. اگه توی بدنه کامپوزبل این کار رو انجام بدین، توی هر Recomposition دوباره فراخوانی میشه و ممکنه مشکل ایجاد کنه.
بخش چهارم: ارسال آرگومانها
گاهی لازم میشه که دادههایی رو بین صفحات ارسال کنیم. توی Compose این کار رو با آرگومانها انجام میدیم.
اگه فرق بین آرگومان و پارامتر رو نمیدونی پیشنهاد میدم این مطلب رو بخونی :تفاوت بین آرگومان و پارامتر :Argument or Parameter
تعریف آرگومانها
آرگومانها دو نوع دارن:
- آرگومانهای اجباری (Required): اینا همیشه باید مقدار داشته باشن.
- آرگومانهای اختیاری (Optional): میتونین مقدار پیشفرض براشون تعریف کنین.
ارسال آرگومانها
برای ارسال آرگومان، مقدار رو همراه با مسیر مقصد ارسال میکنیم:
Button(onClick = { navController.navigate("details/123") }) { Text("Go to Details with ID") }
دریافت آرگومانها
برای خوندن آرگومانها توی صفحه مقصد، از NavBackStackEntry
استفاده میکنیم:
val taskId = navController.previousBackStackEntry?.arguments?.getString("taskId")
نکته: حتماً مطمئن بشین که آرگومانهاتون درست تعریف شدن و مقدار دارن.
بخش پنجم: مثال کامل
حالا بیاین یه مثال واقعی بزنیم که همه چیز رو کنار هم ببینیم.
در این مثال ما سه تا فایل خواهیم داشت ،
- MainActivity()
- Screens
- navigationStack()
MainActivity :
این کلاس که مشخصاً کلاس اصلی ماست ، داخلش دوتا اسکرین تعریف کردیم ، MainScreen و DetailScreen حالا در این ها میشه ، صفحه های ما ، در صفحه ای MainScreen ما یه دکمه داریم و یه جای نوشته که بشه اون رو به صفحه DetailScreen ارسال کنیم
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { TrainNavigationTheme { Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { NavigationStack() } } } } } @Composable fun MainScreen(navController: NavController) { val text = remember { mutableStateOf("") } Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, modifier = Modifier.fillMaxSize() ) { OutlinedTextField(value = text.value, onValueChange = { text.value = it }) Button(onClick = { navController.navigate(route = Screens.Detail.route + "?text=${text.value}") }) { Text("Next Screen") } } } @Composable fun DetailScreen(text: String?) { Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, modifier = Modifier.fillMaxSize() ) { Text("Detail Screen") Text("$text") } }
Screens:
فایل Screens
مثل یه نقشه ناوبری برای اپلیکیشن عمل میکنه که توش آدرسها و اسم صفحهها رو مشخص میکنیم. اینجوری همه مسیرها یه جا جمع میشن و مدیریتشون خیلی راحتتر میشه. به جای اینکه توی پروژه از رشتههای پراکنده استفاده کنیم، مسیرها رو اینجا تعریف میکنیم تا هم کد تمیزتر باشه و هم اگه بخوایم چیزی رو تغییر بدیم، سریع پیداش کنیم. خلاصه، این فایل کارمون رو برای مدیریت صفحهها و مسیرهای ناوبری حسابی ساده میکنه!
sealed class Screens(val route:String){ data object Main:Screens("main_screen") data object Detail:Screens("detail_screen") }
navigationStack() :
«بار کلی ، این کار ناوبری بر دوش این فایل عه» ، این فایل در واقع مسئول مدیریت و اجرای ناوبری بین صفحههای اپلیکیشن شماست. توش یه تابع کامپوزبل به اسم NavigationStack
داریم که کارش اینه که یه NavController
بسازه و همه مقصدهای ناوبری رو داخل یه NavHost
تعریف کنه. اینجا مشخص میکنیم کدوم صفحه نقطه شروع باشه (مثل صفحه اصلی یا همون MainScreen
) و چطوری بین صفحهها جابهجا بشیم.
برای هر صفحه (مثل MainScreen
و DetailScreen
) یه مسیر (Route) تعریف کردیم که از فایل Screens
گرفته شده. توی مسیر DetailScreen
حتی یه آرگومان به اسم text
هم داریم که میتونیم مقدارش رو ارسال کنیم. این باعث میشه هر وقت بخوایم چیزی رو به صفحه جزئیات بفرستیم، خیلی راحت این کار رو انجام بدیم. خلاصه، این فایل تمام مسیرها و ارتباط بین صفحهها رو مدیریت میکنه و کار ناوبری رو حسابی ساده و مرتب کرده!
package ir.brazandeh.trainnavigation import androidx.compose.runtime.Composable import androidx.navigation.NavType import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import androidx.navigation.navArgument @Composable fun NavigationStack() { val navController = rememberNavController() NavHost(navController = navController, startDestination = Screens.Main.route) { composable(route = Screens.Main.route) { MainScreen(navController = navController) } composable( route = Screens.Detail.route + "?text={text}", arguments = listOf( navArgument("text") { type = NavType.StringType nullable = true } ) ) { DetailScreen(text = it.arguments?.getString("text")) } } }
بخش ششم: نکات کاربردی
استفاده از popUpTo
: اگه میخواین یه صفحه رو از استک حذف کنین، از popUpTo
استفاده کنین:
navController.navigate("home") { popUpTo("home") { inclusive = true } }
مدیریت آرگومانها: برای ارسال دادههای پیچیده، فقط شناسه (ID) اون داده رو بفرستین و توی صفحه مقصد، داده کامل رو از دیتابیس بگیرین.
جمعبندی
توی این جزوه با Navigation Component در Jetpack Compose آشنا شدین. یاد گرفتین چطوری مقصدها رو تعریف کنین، دادهها رو بین صفحات جابهجا کنین و از NavController
استفاده کنین. امیدوارم این آموزش براتون مفید بوده باشه. اگه سوالی دارین، حتماً بپرسین. موفق باشین! 🚀