在前一章节的完结中,Skeleton: Main structure,咱们留下了几个 Jetpack 架构组件,这些组件将在本章中运用,例如 Composables、ViewModels、Navigation 和 Hilt。此外,咱们还经过 Scaffold 集成了 TopAppBar 和 BottomAppBar UI 形式的根本结构。为了持续改进这个完结,咱们需求增加一个新的要害选项卡,即“应用程序的通用状况”。

App程序的状况:一般状况

界说导航地图

导航从其他UI元素

摘要


应用程序状况:一个通用状况

“规划准则”中咱们讨论了状况在现代 Android 应用程序中的重要作用。
规划中或许存在三种类型的状况:特点 UI 状况、组件 UI 状况和屏幕 UI 状况。
除了这些状况之外,咱们还能够界说一种新类型的状况,即应用程序状况。
这个新状况将界说应用程序的通用状况。它将用于屏幕之间的导航、自发消息(snackbars)的出现以及应用程序中其他可用的进程。
在主目录中,咱们将界说一个名为 OrderNowState 的类,它将是咱们的状况持有者,代表这种类型的状况。

为Android构建现代应用——应用导航设计
为Android构建现代应用——应用导航设计​修正

接下来,咱们像这样履行OrderNowState的初始完结:

@SuppressLint("RememberReturnType")
@Composable
fun rememberAppState(scaffoldState:ScaffoldState=rememberScaffoldState(),
                     navController: NavHostController =rememberNavController(),
                     resources1: Resources = resources(),
                     coroutineScope: CoroutineScope=rememberCoroutineScope()
)=remember(scaffoldState,navController,resources1,coroutineScope){
   OrderNowState(scaffoldState,navController,resources1,coroutineScope)
}
class OrderNowState(val scaffoldState:ScaffoldState,val navController:NavHostController,private val resources:Resources,coroutineScope:CoroutineScope)
@Composable
@ReadOnlyComposable
fun resources():Resources{
    LocalConfiguration.current
    return LocalContext.current.resources
}

为Android构建现代应用——应用导航设计

然后,咱们修正咱们的OrderNowScreen视图以包括之前界说的状况,如下所示:
@Preview
@Composable
fun OrderNowScreen(){
    MyTestTheme {
        Surface(modifier = Modifier.fillMaxSize(),color=MaterialTheme.colors.background) {
            val appState =rememberAppState()
            Scaffold(scaffoldState = appState.scaffoldState, topBar = { OrderNowTopBar()}, bottomBar = {OrderNowBottomBar()}){contentPadding->
                println(contentPadding)
            }
        }
    }
}

为Android构建现代应用——应用导航设计

留意:

还需求向OrderNowScreen增加资源函数,它将运用该函数访问App资源。

突出显现更改的代码行如下:

  Scaffold(
                scaffoldState = appState.scaffoldState,
                topBar = { OrderNowTopBar() },
                bottomBar = { OrderNowBottomBar() }) { contentPadding ->
                println(contentPadding)
            }

为Android构建现代应用——应用导航设计

有了上面的代码,咱们现在能够告知Scaffold它应该把哪个状况作为引证:应用程序的状况。之后,视图之间的导航操作、自发消息的出现,以及视图只把AppState作为实在源的其他独占任务都将被答应。

既然现已为APP界说了状况,咱们就能够持续完结APP的导航了。

界说导航地图

咱们在应用程序中运用的导航战略由以下元素组成:

NavHost:它是担任在视图中显现导航结果的组件。导航的结果由NavigationController和导航图中给出的界说决议。

AppSoGraph:它是导航图的完结。它应该根据指定的路由将导航指向哪个视图或可组合目标。

屏幕路由: 它们是能够经过导航到达的应用程序的不同屏幕。不管导航是从选项菜单、链接、按钮仍是任何其他活动署理激活的,都无关紧要。每个屏幕都有一个与之相关的唯一路由。

一般导航图

为Android构建现代应用——应用导航设计
为Android构建现代应用——应用导航设计​修正

咱们将持续在OrderNow中包括这些元素

OrderNowScreenRoute

首要,创立一个名为common -> navigation的新遍历目录。在这个包中,咱们像这样增加了一个名为OrderNowScreenRoute的类:

为Android构建现代应用——应用导航设计
为Android构建现代应用——应用导航设计​修正

在这个类中,能够导航到的屏幕界说如下:

sealed class OrderNowScreenRoute(val route:String){
    object Home :OrderNowScreenRoute("home")
    object Cart:OrderNowScreenRoute("cart")
    object ProductList:OrderNowScreenRoute("product_list")
    object ProductDetail:OrderNowScreenRoute("product_detail")
}

为Android构建现代应用——应用导航设计

OrderNowNavHost 和 AppSoGraph

现在,咱们创立OrderNowNavHost类,它将像这样表明应用程序的NavHost:

为Android构建现代应用——应用导航设计
为Android构建现代应用——应用导航设计​修正

@Composable
fun OrderNowNavHost(appState:OrderNowState){
    NavHost(navController = appState.navController,5,startDestination=1){
        appSoGraph(appState)
    }
}
fun NavGraphBuilder.appSoGraph(appState: OrderNowState) {
}

为Android构建现代应用——应用导航设计

从之前的代码片段中,咱们应该着重以下界说:
• OrderNowNavHost 需求知道 APP 的状况。
• NavController 是从 APP 状况中保管和获取的。
• Navigation map(appSoGraph)将基于 APP 的状况创立,并且是在 OrderNowNavHost 内界说的扩展。
为了持续完结 OrderNow 中导航的完结,咱们有必要增加一个描述如下的辅佐类。
NavigationBarSection
NavigationBarSection 是一个辅佐类,代表应用程序底部菜单中组成筛选组的部分。
请记住,咱们能够从选项菜单或其他 UI 组件(如链接、按钮或内部重定向)中的操作开端导航。
在下一节中,咱们将对内部重定向(从按钮、链接等)进行更改;现在,让咱们专心于从 BottomBar 导航。

为Android构建现代应用——应用导航设计
为Android构建现代应用——应用导航设计​修正

咱们看到NavigationBarSection协助器类将如何只对Home和Cart屏幕进行分组,这是咱们期望从BottomBar菜单启用的选项。这个类将像这样放置在导航目录中:

为Android构建现代应用——应用导航设计
为Android构建现代应用——应用导航设计​修正

它的完结是这样的:

sealed class OrderNowScreenRoute(val route:String){
    object Home :OrderNowScreenRoute("home")
    object Cart:OrderNowScreenRoute("cart")
    object ProductList:OrderNowScreenRoute("product_list")
    object ProductDetail:OrderNowScreenRoute("product_detail")
}
sealed class NavigationBarSection(val title: String, val icon: ImageVector, val route:String){
    companion object{
        val sections = listOf(OrderNowScreenRoute.Home,OrderNowScreenRoute.Cart)
    }
    object Home:NavigationBarSection(title ="Home" , icon = Icons.Default.Home, route =OrderNowScreenRoute.Home.route)
    object Cart:NavigationBarSection(title = "Cart", icon =Icons.Default.ShoppingCart, route = OrderNowScreenRoute.Cart.route)
}

为Android构建现代应用——应用导航设计

将helper类增加到项目中后,咱们持续更新OrderNowNavHost类,如下所示:

@Composable
fun OrderNowNavHost(appState: OrderNowState, paddingValues: PaddingValues) {
    NavHost(
        navController = appState.navController,
        startDestination = NavigationBarSection.Home.route,
        modifier = Modifier.padding(paddingValues)
    ) {
        appSoGraph(appState)
    }
}
fun NavGraphBuilder.appSoGraph(appState: OrderNowState) {
    composable(NavigationBarSection.Home.route) {
       // HomeScreen()
    }
    composable(NavigationBarSection.Cart.route) {
       // CartScreen()
    }
    composable(OrderNowScreenRoute.ProductList.route){
        //ProductListScreen()
    }
    composable(OrderNowScreenRoute.ProductDetail.route){
        //ProductDetailScreen()
    }
}

为Android构建现代应用——应用导航设计

appSoGraph函数的完结是NavGraphBuilder的扩展,在那里,咱们为App的每个屏幕指定导航地图。另外,经过startDestination参数,指定将首要出现的默许屏幕,即Home屏幕。选用更改的下一步是更新名为 OrderNowBottomBar 的类,如下所示:

@Composable
fun OrderNowBottomBar(navController: NavHostController) {
    val navBackStackEntry by navController.currentBackStackEntryAsState()
    val currentDestination = navBackStackEntry?.destination
    BottomNavigation(
        backgroundColor = MaterialTheme.colors.background,
        contentColor = contentColorFor(MaterialTheme.colors.background),
        elevation = 10.dp
    ) {
        NavigationBarSection.sections.forEach { section ->
            val selected = currentDestination?.hierarchy?.any {
                it.route == section.route
            } == true
            BottomNavigationItem(icon = {
                Icon(
                    imageVector =  ImageVector.vectorResource(R.drawable.ic_launcher_foreground),
                    contentDescription = stringResource(id = R.string.app_name)
                )
            },
                label = { Text(text = stringResource(id =R.string.app_name)) },
                selected = selected,
                unselectedContentColor = Color.Gray,
                selectedContentColor = Color.Red,
                onClick = {
                    navController.navigate(section.route) {
                        popUpTo(navController.graph.findStartDestination().id) {
                            saveState = true
                        }
                        launchSingleTop = true
                        restoreState = true
                    }
                })
        }
    }
}

为Android构建现代应用——应用导航设计

关于增加到 NavigationBarSection 中的每个项目,BottomBar 中都会显现一个选项。OrderNowBottomBar 的这个完结比之前的架构:首要结构中的完结更明晰。

然后,咱们再次更新 OrderNowScreen 视图,如下所示:


@Preview
@Composable
fun OrderNowScreeen(){
    MyTestTheme(){
        Surface {
            val appState =rememberAppState()
            Scaffold(
                scaffoldState = appState.scaffoldState,
                topBar = {OrderNowTopBar()},
                bottomBar = {OrderNowBottomBar(appState.navController)}
            ){contentPadding ->
                OrderNowNavHost(appState,contentPadding)
            }
        }
    }
}

为Android构建现代应用——应用导航设计

现在 OrderNowBottomBar 将需求引证担任导航的 navController。

在Scaffold的内容部分,增加了OrderNowNavHost的实例,该实例接纳APP的一般状况作为参数。Order Now with simple navigation:

为Android构建现代应用——应用导航设计
为Android构建现代应用——应用导航设计​修正

从其他UI元素进行导航

现在咱们现已准备好从 BottomBar 选项导航的完结,咱们需求界说从其他 UI 元素(例如按钮、链接、DeepLinks)乃至根据应用程序的其他内部组件的恳求以编程方式导航应用程序。咱们要做的第一个更改是增加一个名为 OrderNowNavigationState 的结构,它答应咱们扩展应用程序的一般状况。

为Android构建现代应用——应用导航设计
为Android构建现代应用——应用导航设计​修正

OrderNowNavigationState,是APP通用状况的扩展,即一组用于导航意图的OrderNowState状况的扩展。咱们还将运用此结构来会集取决于应用程序状况的导航逻辑。

为Android构建现代应用——应用导航设计
为Android构建现代应用——应用导航设计​修正

OrderNowNavigationState的完结如下:


fun OrderNowState.popUp(){
    navController.popBackStack()
}
fun OrderNowState.navigate(route:String){
    navController.navigate(route){
        launchSingleTop  = true
    }
}
fun OrderNowState.navigateAndPopUp(route:String,popUp:String){
    navController.navigate(route){
        launchSingleTop =true
        popUpTo(popUp){
            inclusive =true
        }
    }
}
fun OrderNowState.navigateSaved(route:String,popUp:String){
    navController.navigate(route){
        launchSingleTop =true
        restoreState =true
        popUpTo(popUp){
            saveState =true
        }
    }
}
fun OrderNowState.clearAndNavigate(route:String){
    navController.navigate(route){
        launchSingleTop =true
        popUpTo(0){ inclusive =true}
    }
}

为Android构建现代应用——应用导航设计

对Home、ProductList和ProductDetail屏幕做了一些更改,如下图所示:

为Android构建现代应用——应用导航设计
为Android构建现代应用——应用导航设计​修正

以in – home视图为例,导航动作经过Button履行,方式如下:


@Composable
fun HomeScreen(goToProductList:()->Unit,modifier:Modifier=Modifier,viewModel2:HomeViewModel =hiltViewModel()){
    Column(){
        Button(onClick = goToProductList,){
            Text(text = stringResource(id = R.string.app_name))
        }
    }
}

为Android构建现代应用——应用导航设计

代码的重要部分是“Go to —> ProductList Screen”按钮的动作 onClick = goToProductList 的界说,其间经过规划原理章节中解说的状况提高技能,咱们将动作 goToProductList 托付给在 OrderNowNavHost 中界说的 appSoGraph 导航图如下:

un NavGraphBuilder.appSoGraph1(appState:OrderNowState){
    val goToListFromHome:()->Unit ={
        appState.navigateSaved(OrderNowScreenRoute.ProductList.route,OrderNowScreenRoute.Home.route)
    }
    composable(NavigationBarSection.Home.route){
        HomeScreen(goToProductList =goToListFromHome)
    }
}

为Android构建现代应用——应用导航设计

回想一下,navigatesave函数是OrderNowNavigationState结构中界说的扩展的一部分。同样的完结应用于导航到其他ProductList和ProductDetail屏幕,这样在OrderNowNavHost中的功用如下所示:

fun  NavGraphBuilder.appSoGraph2(appState:OrderNowState){
    val homeRoute= OrderNowScreenRoute.Home.route
    val listRoute= OrderNowScreenRoute.ProductList.route
    val detailRoute =OrderNowScreenRoute.ProductDetail.route
    val goToListFromHome:()->Unit ={
        appState.navigateSaved(listRoute,homeRoute)
    }
    val goToDetailFromList:()->Unit ={
        appState.navigateSaved(detailRoute,listRoute)
    }
    val goBack:()->Unit ={
        appState.popUp()
    }
    composable(NavigationBarSection.Home.route){
        HomeScreen(goToProductList =goToListFromHome)
    }
    composable(NavigationBarSection.ProductList.route){
        ProductListScreen(goToProductDetail =goToDetailFromList,goBack =goBack)
    }
    composable(NavigationBarSection.ProductDetail.route){
        ProductDetailScreen(goBack =goBack)
    }
}

为Android构建现代应用——应用导航设计

总结起来,前面的代码段中配置了以下导航界说(导航图):

  1. 从主页(Home screen)导航到产品列表(ProductList screen)。
  2. 从产品列表(ProductList screen)导航到产品概况(ProductDetail screen)。
  3. 从产品概况(ProductDetail screen)导航回到上一个出现的屏幕。
  4. 从底部导航栏菜单导航到主页(Home screen)。
  5. 从底部导航栏菜单导航到购物车(Cart screen)。

到此为止,咱们在 OrderNow 应用中现已完结了一个很好的根本导航。然而,还有一些东西缺失。 您有什么主意或许是缺失的吗? 咱们需求在导航中包括数据或信息的传递。 因为在本章中规划了相关的完结,因此很容易完结数据传递。咱们将在最终“完结功用”中具体讨论。

总结

本章中,咱们完结了应用程序的首要部分的规划,这些将是今后增加功用的基础。 咱们知道导航是应用程序的重要组成部分,有必要从应用程序规划的开端就考虑它。 在本章中,咱们选用了谷歌的主张,将状况纳入导航逻辑中。 同时,读者能够留意到咱们的战略中没有直接涉及 ViewModel 或 View,这使得它在测验时更加灵敏,能够查看导航。