小蒋的技术栈记录

小蒋的技术栈记录

《Jetpack Compose从入门到实战》第八章 Compose页面 导航-LMLPHP

  • 添加依赖:implementation “androidx.navigation:navigation-compose:$nav_version”

Navigation for Compose

class MainActivity : AppCompatActivity() {

    var theme: BloomTheme by mutableStateOf(BloomTheme.LIGHT)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {

            AppNavigation()

        }
    }
}

@Composable
fun AppNavigation() {
    val navController = rememberNavController()
    NavHost(navController = navController, startDestination = "home") {
        composable("welcome") {
            WelcomeScreen(navController = navController)
        }
        composable("login") {
            LoginScreen(navController = navController)
        }
        composable("home") {
            HomeScreen(navController = navController)
        }
    }
}

fun WelcomeScreen(navController: NavController) {
    ...
    Button(onClick = { 
        navController.navigate("login") 
    
        navController.navigate("home"){
            popUpTo("welcome")
        }

        navController.navigate("home"){
            popUpTo("welcome"){ inclusive = true}
        }

        navController.navigate("home"){
            launchSingleTop = true
        }
    }) {
        Text(text = "Login in")
    }

    ...
}

导航时携带参数

NavHost(...) {
        composable(
            "plantDetail/{plantId}/{fromBanner}",
            arguments = listOf(
                navArgument("plantId"){type=NavType.IntType},
                navArgument("fromBanner"){type=NavType.BoolType}
            )
        )
    }

NavHost(...) {
        composable(
            "plantDetail/{plantId}?fromBanner={fromBanner}",
            arguments = listOf(
                navArgument("fromBanner"){
                    type=NavType.BoolType
                    defaultValue = false
                }
            )
        )
    }
  • 推荐用Id之类的索引参数传递,然后从本地或远程数据源请求
  • 尽量为导航参数添加默认值
sealed class Screen(
    val route: String,
    @StringRes val resourceId: Int,
    val icon: ImageVector
){
    object Home:Screen("home",R.string.home, Icons.Filled.Home)
    object Favorite:Screen("home",R.string.favorite, Icons.Filled.Favorite)
    object Profie:Screen("home",R.string.profie, Icons.Filled.Profie)
    object Cart:Screen("home",R.string.cart, Icons.Filled.Cart)
}

val items = listOf(Screen.Home,Screen.Favorite,Screen.Profie,Screen.Cart)
val navController = rememberNavController()
    Scaffold(
        bottomBar = {
            BottomNavigation{
                val navBackStackEntry by navController.currentBackStackEntryAsState()
                val currentDestination = navBackStackEntry?.destination
                items.forEach { screen ->
                    BottomNavigationItem(
                        icon = { Icon(imageVector = screen.icon,
                            contentDescription = null) },
                        label = { Text(text = stringResource(screen.resourceId)) },
                        selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
                        selectedContentColor = Color.Red,
                        unselectedContentColor = Color.Gray,
                        onClick = {
                            navController.navigate(screen.route) {
                                // Pop up to the start destination of the graph to
                                // avoid building up a large stack of destinations
                                // on the back stack as users select items
                                popUpTo(navController.graph.findStartDestination().id) {
                                    saveState = false
                                }
                                // Avoid multiple copies of the same destination when
                                // reselecting the same item
                                launchSingleTop = true
                                // Restore state when reselecting a previously selected item
                                restoreState = false
                            }
                        }
                    )
                }
            }
        }
    ) { innerPadding ->
        NavHost(navController, startDestination = Screen.Home.route, Modifier.padding(innerPadding)) {
            composable(Screen.Home.route) { HomeScreen(navController) }
            composable(Screen.Favorite.route) { FavoriteScreen(navController) }
            composable(Screen.Cart.route) { CartScreen(navController) }
            composable(Screen.Profile.route) { ProfileScreen(navController) }
        }
}

嵌套导航图 Nested Navigation Graph

  • 一个App Module 由多个Lib Module组成
  • 添加lib依赖
  • 设置根NavHost和子NavHost

导航DeepLinks

  • 跨模块跳转或者跨进程跳转,最好用这个

依赖注入

待补充

sealed class Screen(
    val route: String,
    val title: String,
    val icon: ImageVector
) {
    object Home : Screen("home", "home", Icons.Filled.Home)
    object Favorite : Screen("favorite", "favorite", Icons.Filled.Favorite)
    object Notification : Screen("notification", "notification", Icons.Filled.Notifications)
    object Cart : Screen("cart", "cart", Icons.Filled.ShoppingCart)
}

val items = listOf(Screen.Home, Screen.Favorite, Screen.Notification, Screen.Cart)

val uri = "android-app://compose.learn"

@Preview
@Composable
fun Navigation2() {
    val navController = rememberNavController()
    Scaffold(bottomBar = {
        BottomNavigation {
            val navBackStackEntry by navController.currentBackStackEntryAsState()
            val currentDestination = navBackStackEntry?.destination
            items.forEach { screen ->
                BottomNavigationItem(selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
                    onClick = {
                        navController.navigate(screen.route) {
                            popUpTo(navController.graph.findStartDestination().id) {
                                saveState = true
                            }
                            launchSingleTop = true
                            restoreState = true
                        }
                    },
                    icon = {
                        Icon(screen.icon, contentDescription = "")
                    },
                    label = { Text(text = screen.title) })
            }
        }
    }) { innerPadding ->
        //deep link test:  adb shell am start -d "android-app://compose.learn/notification/adbTest" -a android.intent.action.VIEW
        NavHost(navController = navController, startDestination = Screen.Home.route, modifier = Modifier.padding(innerPadding)) {
            composable(Screen.Home.route) { navBackStackEntry ->
                //viewModel()以composable为ViewModelStore,作用域只在当前的composable中
                val exampleViewModel: ExampleViewModel = viewModel()
                //多个destination之间共享viewmodel可以使用以下方法传入一个公共的ViewModelStoreOwner,这里是navBackStackEntry, 在多层路由下可以这样使用
                val exampleViewModel2 = hiltViewModel<ExampleViewModel2>(navBackStackEntry)
                Home()
            }
            composable(Screen.Favorite.route) { Favorite() }
            composable(
                Screen.Notification.route,
                deepLinks = listOf(navDeepLink { uriPattern = "$uri/notification/{from}" })
            ) { backStackEntry ->
                Notification(backStackEntry.arguments?.getString("from"))
            }
            composable(Screen.Cart.route) { Cart() }
        }
    }
}

@Composable
fun Home() {
    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        Text(text = "Home")
    }
}

@Composable
fun Favorite() {
    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        Text(text = "Favorite")
    }
}

@Composable
fun Notification(from: String?) {
    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        Text(text = "Notification from $from")
    }
}

@Composable
fun Cart() {
    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        Text(text = "Cart")
    }
}

class ExampleViewModel : ViewModel() {

}

@HiltViewModel
class ExampleViewModel2 @Inject constructor() : ViewModel() {

}

10-02 02:06