Jetpack Navigation 3 යනු කුමක්ද? Jetpack Navigation 3 යනු නව Google නාවික පුස්තකාලය වන අතර එය පෙර ප්රදර්ශන වලින් මූලිකව වෙනස් වේ. — සාමාන්ය mutable ලැයිස්තුව, එහිදී සෑම අංගයක්ම ඔබගේ යෙදුම තුළ රූපයක් නියෝජනය කරයි. NavBackStack ඔබ මෙම ලැයිස්තුවෙන් අමුද්රව්ය එකතු කිරීම සහ ඉවත් කිරීම, සහ UI ස්වයංක්රීයව යාවත්කාලීන කරයි. සාමාන් ය කොට්ලන් පන්තිය NavKey මෙය ඔබට ප්රවේශය පිළිබඳ සම්පූර්ණ පාලනය ලබා දෙයි, නමුත් සාමාන් ය ක්රියාකාරකම් සඳහා බොහෝ කැටයම් කේතයක් ලිවීමට අවශ්ය වේ. NavBackStack සමඟ සෘජුවම වැඩ කිරීම අපහසු වන්නේ ඇයි අපි සෘජුවම වැඩ කරන විට කේතය පෙනෙන ආකාරය බලන්න : NavBackStack @Composable fun MyApp() { val backStack = rememberNavBackStack(Screen.Home) // Add a screen backStack.add(Screen.Details("123")) // Go back backStack.removeLastOrNull() // Replace current screen backStack.set(backStack.lastIndex, Screen.Success) } ප්රශ්න ආරම්භ වන විට ඔබ ViewModel සිට ප්රවේශය ක්රියාත්මක කිරීමට අවශ්ය වේ. ViewModel (මම හිතන්නේ ViewModel Compose-පෞද්ගලික දේවල් ගැන දන්නේ නැති නිසා, මගේ තේරුම අනුව, අඛණ්ඩ මූලධර්මයවලට විරුද්ධ වන) හෝ සෑම ප්රවේශ ක්රියාවලියකටම මධ්යම callbacks නිර්මාණය කරන්න. NavBackStack එපමණක් නොව, ස්කෑම් සමඟ සෘජුවම වැඩ කරන විට, අර්ධ ප්රශ්න කටයුතු කිරීමට අමතක කිරීම පහසු වේ. Nav3 router වැඩ පහසු කරගන්නේ කෙසේද Nav3 Router කියන්නේ Navigation 3 වලට වඩා අලංකාර ආකර්ෂණීය API එකක් සපයන එකයි.Instead of thinking about indices and list operations, you simply say "go to screen X" or "go back". වැදගත් කරුණු: Nav3 router තමන්ගේ ස්පේක් එකක් නිර්මාණය නොකරයි.It works with the same Navigation 3 මගින් ලබා ගත හැක්කේ එය සමඟ වැඩ කිරීම වඩාත් පහසු කිරීම පමණි. , පුස්තකාලය මෙම ප්රතිපත්තිය පරිවර්තනය කරන්නේ මුල් ස්කෑම් සමඟ ගැලපෙන මෙහෙයුමටයි. NavBackStack router.push(Screen.Details) ප් රධාන වාසි : ViewModel භාවිතා කළ හැක UI තාවකාලිකව ලබා ගත නොහැක (උදාහරණයක් ලෙස, screen rotating කාලය තුළ) සියළුම ස්ටැක් මෙහෙයුම් atomically සිදු වේ. පිරිසිදු API වෙනස් කිරීම හා custom behavior එකතු කිරීම සඳහා මෘදුකාංගය ස්ථාපනය Nav3 රූටරය Maven Central මත ලබා ගත හැකිය. : build.gradle.kts // For shared module in KMP project kotlin { sourceSets { commonMain.dependencies { implementation("io.github.arttttt.nav3router:nav3router:1.0.0") } } } // For Android-only project dependencies { implementation("io.github.arttttt.nav3router:nav3router:1.0.0") } GitHub හි ප් රවෘත්ති කේතය ලබා ගත හැකිය: github.com/arttttt/Nav3Router Nav3 router එක හදන්නේ කොහොමද පුස්තකාලයේ ප් රධාන කොටස් තුනක් ඇත, සෑම කොටසක්ම තමන්ගේම කාර්යය විසඳයි: Router - පරිගණක පරිගණක Router වැනි ක්රමයන් සපයයි , , ඔබ මෙම ක්රම ඇමතුම් කරන විට, රවුටරය ගැලපෙන නියෝග නිර්මාණය කරයි සහ ඒවා සෝදිසි කරයි.රවුටරය විසින් එය ක්රියාත්මක කරන ආකාරය ගැන කිසිවක් දන්නේ නැත - එය ඕනෑම තැනක සිට භාවිතා කිරීමට ඉඩ ඇත. push() pop() replace() CommandQueue – Commands සහ Execution අතර Buffer CommandQueue වේලාව ගැටලුව විසඳා ඇත. සිතුවිලි: පරිශීලකයා ස්කෑන් රෝටකය තුළ බොත්තම පීඩනය කර ඇත. පරිගණක පරිශීලක පරිශීලකයා නැවත නිර්මාණය කර ඇත, සහ නාවිකය තාවකාලිකව ලබා ගත නොහැකි වේ. CommandQueue නියෝගයක් ඉතිරි කරනු ඇත සහ නාවිකය නැවත සූදානම් වන විට එය ක්රියාත්මක කරනු ඇත. // Simplified queue logic class CommandQueue<T : Any> { private var navigator: Navigator<T>? = null private val pending = mutableListOf<Command<T>>() fun executeCommand(command: Command<T>) { if (navigator != null) { navigator.apply(command) // Navigator exists - execute immediately } else { pending.add(command) // No - save for later } } } Navigator - Stack සමග වැඩ කරන කෙනා Navigator එකෙන් Commands ගන්නවා. වැදගත් විස්තරයක්: එය පළමුවෙන්ම වර්තමානයේ තැපැල් පිටපතක් නිර්මාණය කරයි, එය සඳහා සියලු නියෝග ක්රියාත්මක කරයි, පසුව ප්රථම තැපැල් තැපැල් වෙනස් කරන ලද පිටපතක් සමඟ අමුද්රව්ය ලෙස මාරු කරයි. NavBackStack // Simplified Navigator logic fun applyCommands(commands: Array<Command>) { val stackCopy = backStack.toMutableList() // Work with a copy for (command in commands) { when (command) { is Push -> stackCopy.add(command.screen) is Pop -> stackCopy.removeLastOrNull() // ... other commands } } backStack.swap(stackCopy) // Atomically apply changes } Nav3 Router සමඟ ආරම්භ කිරීම සරලම ක් රමය - මෑතින්ම Router නිර්මාණය නොකරන්න. Nav3Host ඔබ වෙනුවෙන් එය කරයි: @Composable fun App() { val backStack = rememberNavBackStack(Screen.Home) // Nav3Host will create Router automatically Nav3Host(backStack = backStack) { backStack, onBack, router -> NavDisplay( backStack = backStack, onBack = onBack, entryProvider = entryProvider { entry<Screen.Home> { HomeScreen( onOpenDetails = { router.push(Screen.Details) // Use router } ) } entry<Screen.Details> { DetailsScreen( onBack = { router.pop() } ) } } ) } } වඩාත් සංකීර්ණ යෙදුම් සඳහා, DI හරහා රවුටරය නිර්මාණය කිරීම සහ එය ViewModel වෙත මාරු කිරීම තේරුම් ගත හැකිය: Screens සකස් කිරීම @Serializable sealed interface Screen : NavKey { @Serializable data object Home : Screen @Serializable data class Product(val id: String) : Screen @Serializable data object Cart : Screen } Router එක Nav3Host වෙත මාරු කරන්න. @Composable fun App() { val backStack = rememberNavBackStack(Screen.Home) val router: Router<Screen> = getSomehowUsingDI() // Pass Router to Nav3Host Nav3Host( backStack = backStack, router = router, ) { backStack, onBack, _ -> NavDisplay( backStack = backStack, onBack = onBack, entryProvider = entryProvider { entry<Screen.Home> { HomeScreen() } entry<Screen.Details> { DetailsScreen() } } ) } } ViewModel constructor හරහා Router ලබා ගනී. class ProductViewModel( private val router: Router<Screen>, private val cartRepository: CartRepository ) : ViewModel() { fun addToCart(productId: String) { viewModelScope.launch { cartRepository.add(productId) router.push(Screen.Cart) // Navigation from ViewModel } } } ViewModel භාවිතා කරන්න. @Composable fun ProductScreen(viewModel: ProductViewModel = koinViewModel()) { Button(onClick = { viewModel.addToCart(productId) }) { Text("Add to Cart") } } Typical Scenarios උදාහරණ පහසු ඉදිරියට ආපසු නැව්ගත කිරීම // Navigate to a new screen router.push(Screen.Details(productId)) // Go back router.pop() // Navigate with replacement of current screen (can't go back) router.replaceCurrent(Screen.Success) Screen Chains සමඟ වැඩ කිරීම // Open multiple screens at once router.push( Screen.Category("electronics"), Screen.Product("laptop-123"), Screen.Reviews("laptop-123") ) // Return to a specific screen // Will remove all screens above Product from the stack router.popTo(Screen.Product("laptop-123")) Checkout සිතුවිලි @Composable fun CheckoutScreen(router: Router<Screen>) { Button( onClick = { // After checkout we need to: // 1. Show confirmation screen // 2. Prevent going back to cart router.replaceStack( Screen.Home, Screen.OrderSuccess(orderId) ) // Now only Home and OrderSuccess are in the stack } ) { Text("Place Order") } } නැව්ගත කිරීම Nested Navigation // User is deep in settings: // Home -> Settings -> Account -> Privacy -> DataManagement // "Done" button should return to home Button( onClick = { // Will leave only root (Home) router.clearStack() } ) { Text("Done") } // Or if you need to close the app from anywhere Button( onClick = { // Will leave only current screen and trigger system back router.dropStack() } ) { Text("Exit") } ප්රසාද: SceneStrategy සහ Dialogs මෙතෙක් අපි කතා කලේ තැපැල් අතර සරල ප්රවේශය ගැන පමණි.ඒත් ඔබ සන්නිවේදන හෝ පහත පිටුව පෙන්වන්න අවශ්ය නම් කුමක්ද? SceneStrategy යනු කුමක්ද? SceneStrategy යනු ඔබේ ස්කෑන් එකෙන් පෙනෙන ස්කෑන් ක් රමය නිවැරදිව තීරණය කරන ක් රමයකි. නමුත් ඔබ වඩාත් සංකීර්ණ තත්ත්වයන් සඳහා ඔබේම උපාය මාර්ග නිර්මාණය කළ හැකිය. SinglePaneSceneStrategy SceneStrategy ගැන අධ් යක්ෂවරයකු ලෙස සිතන්න, ඔබගේ ස්කෑන් කට්ටලය දිහා බැලූ අතර තීරණය කරයි: "ඔව්, අපි සාමාන්යයෙන් මෙම රූප තුනක් පෙන්වා දෙන්නෙමු, නමුත් මේ අවසාන එක - පසුගිය කට්ටලයට වඩා ප්රමාණවත් ජනේලයක් ලෙස" මෙය එකම කට්ටලය සමඟ විවිධ UI ආකෘති ඉදිරිපත් කිරීමට ඉඩ සලසයි. ModalBottomSheet සඳහා උපාය මාර්ගයක් නිර්මාණය කිරීම පළමුව, අපි එවැනි ස්කෑන් සලකා බලන්නේ කෙසේද යන්න තීරණය කරමු: @Serializable sealed interface Screen : NavKey { @Serializable data object Home : Screen @Serializable data class Product(val id: String) : Screen // This screen will be shown as bottom sheet @Serializable data object Filters : Screen } දැන්, අපි තනි උපායමාර්ගයක් නිර්මාණය කරමු.එය අවසාන රූපයේ මෙටා දත්ත පරීක්ෂා කරනු ඇත, එය විශේෂ මාක්ටර් සොයා ගන්නේ නම්, එය පහත ලැයිස්තුවක් ලෙස පෙන්වයි: class BottomSheetSceneStrategy<T : Any> : SceneStrategy<T> { companion object { // Metadata key by which we identify bottom sheet private const val BOTTOM_SHEET_KEY = "bottomsheet" // Helper function to create metadata fun bottomSheet(): Map<String, Any> { return mapOf(BOTTOM_SHEET_KEY to true) } } @Composable override fun calculateScene( entries: List<NavEntry<T>>, onBack: (Int) -> Unit ): Scene<T>? { val lastEntry = entries.lastOrNull() ?: return null // Check if the last screen has bottom sheet marker val isBottomSheet = lastEntry.metadata[BOTTOM_SHEET_KEY] as? Boolean if (isBottomSheet == true) { // Return special Scene for bottom sheet return BottomSheetScene( entry = lastEntry, previousEntries = entries.dropLast(1), onBack = onBack ) } // This is not a bottom sheet, let another strategy handle it return null } } විවිධ උපාය මාර්ග සමන්විත කිරීම සැබෑ යෙදුම තුළ, ඔබට පහත පිටුව, සන්නිවේදන සහ සාමාන්ය ස්කෑන් අවශ්ය විය හැකිය.මේ සඳහා, ඔබ සෑම ස්කෑන් සඳහා නිවැරදි උපාය මාර්ග තෝරා ගනු ලබන නියෝජිත උපාය මාර්ගයක් නිර්මාණය කළ හැකිය: class DelegatedScreenStrategy<T : Any>( private val strategyMap: Map<String, SceneStrategy<T>>, private val fallbackStrategy: SceneStrategy<T> ) : SceneStrategy<T> { @Composable override fun calculateScene( entries: List<NavEntry<T>>, onBack: (Int) -> Unit ): Scene<T>? { val lastEntry = entries.lastOrNull() ?: return null // Check all keys in metadata for (key in lastEntry.metadata.keys) { val strategy = strategyMap[key] if (strategy != null) { // Found suitable strategy return strategy.calculateScene(entries, onBack) } } // Use default strategy return fallbackStrategy.calculateScene(entries, onBack) } } භාවිතයේ යෙදුම දැන්, අපි එය සියල්ල එකතු කරමු. මෙන්න සැබෑ අයදුම්පත තුළ පහත ලැයිස්තුව භාවිතා කරන ආකාරය: @Composable fun ShoppingApp() { val backStack = rememberNavBackStack(Screen.Home) val router = rememberRouter<Screen>() Nav3Host( backStack = backStack, router = router ) { backStack, onBack, router -> NavDisplay( backStack = backStack, onBack = onBack, // Use our combined strategy sceneStrategy = DelegatedScreenStrategy( strategyMap = mapOf( "bottomsheet" to BottomSheetSceneStrategy(), "dialog" to DialogSceneStrategy() // Navigation 3 already has this strategy ), fallbackStrategy = SinglePaneSceneStrategy() // Regular screens ), entryProvider = entryProvider { entry<Screen.Home> { HomeScreen( onOpenFilters = { // Open filters as bottom sheet router.push(Screen.Filters) } ) } entry<Screen.Product> { screen -> ProductScreen(productId = screen.id) } // Specify that Filters should be bottom sheet entry<Screen.Filters>( metadata = BottomSheetSceneStrategy.bottomSheet() ) { FiltersContent( onApply = { filters -> // Apply filters and close bottom sheet applyFilters(filters) router.pop() } ) } } ) } } මොනවද මේ වෙන්නෙ?ඔයා කෝල් කරනකොට නමුත් මෙටා දත්ත සහ අපගේ උපාය මාර්ගයෙන්, පරිගණක පරිශීලකයා තේරුම් ගන්නේ මෙම රූපය පසුගිය රූපයේ ඉහළට පහළ කොටසක් ලෙස පෙන්විය යුතු බව, එය සම්පූර්ණයෙන්ම මාරු කිරීම වෙනුවට. router.push(Screen.Filters) කෝල් කරනකොට පහත පෙට්ටිය වසා ඇත, ඔබ පෙර තිරයට නැවත පැමිණෙනු ඇත.රූටරයගේ ප්රවේශය අනුව, මෙය සාමාන්ය ආපසු ප්රවේශය වේ, නමුත් දර්ශනීයව එය මෝඩ වින්ඩෝව වසා දමනවා වගේ පෙනේ. router.pop() මෙම ප්රවේශයේ වාසි SceneStrategy භාවිතා කිරීම වැදගත් ප්රතිලාභ කිහිපයක් සපයයි. පළමුව, ඔබගේ ප්රවේශ ප්රවේශය සරලව පවතී — ඔබ තවමත් භාවිතා සහ දෙවනුව, ප්රවේශ තත්වය අනුකූලව පවතී — පහළ පිටුව පමණක් තවත් ස්කෑන් එකක ස්කෑන් ක්රියාත්මක කිරීම හෝ ක්රියාවලිය මරා දැමීමේදී නිවැරදිව රඳවා තබා ඇති අතර අවසාන වශයෙන්, එය විශිෂ්ට මෘදුකාංගයක් සපයයි — ඔබ පහසුවෙන් ප්රවේශ සංකේතය වෙනස් කිරීමෙන්, ප්රවේශ ප්රවේශ සංකේතය සඟරාවකින් තොරව එහි මෙටා දත්ත වෙනස් කිරීමෙන්. push pop උදාහරණයක් ලෙස, යෙදුම ප්රථම යෙදුම ආරම්භ කරන විට සාමාන්ය ස්කෑන් සහ බලපත්රයක් අවශ්ය ක්රියාවලිය ක්රියාත්මක කිරීමට උත්සාහ කරන විට ආකෘති සන්නිවේදනය විය හැකිය.For example, a login screen can be a regular screen at first app launch and a modal dialog when trying to perform an action that requires authorization. ඔබ Nav3 router භාවිතා කරන්නේ ඇයි? Nav3 Router Navigation 3 වෙනුවට හෝ නව ක්රියාකාරකම් එකතු කිරීමට උත්සාහ නොකරයි. එහි කාර්යය ප්රවේශය සමඟ වැඩ කිරීම පහසු හා අනාවැකිමත් කිරීමයි. ඔබ යෙදුම ඕනෑම මට්ටමේ සිට භාවිතා කළ හැකි සරල API ලබා ගත හැකිය, වේලාව ගැටළු සඳහා ස්වයංක්රීය ප්රතිකාර, සහ පහසුවෙන් ප්රවේශ ලෝහය පරීක්ෂා කිරීමට හැකියාව. එමෙන්ම, කොප්පුව යටතේ, සාමාන්ය නාවික 3 තවමත් එහි සියලු හැකියාවන් සමඟ ක්රියා කරයි: තත්වය ඉතිරි කිරීම, ඇනෝමියා සහාය, සහ පද්ධතිය "පරමු" බොත්තම නිවැරදි කළමනාකරණය. ඔබ දැනටමත් Navigation 3 භාවිතා කරන්නේ නම් හෝ එය වෙත මාරු කිරීමට සැලසුම් කරන්නේ නම්, Nav3 Router ව්යාපෘතියට අනවශ්ය සංකීර්ණතාවක් එකතු නොකිරීමෙන් මෙම අත්දැකීම වඩාත් විනෝදජනක කිරීමට උපකාරී වනු ඇත. වම් GitHub තැන්පතු: github.com/arttttt/Nav3Router භාවිත උදාහරණ: Repository හි sample folder බලන්න