项目档案

货币转换器示例

我们的下一个例子是货币转换赢博体育程序。这是我们的第一个有两个视图的赢博体育程序,所以我们将看看在赢博体育程序中的视图之间导航所需的机制。第一个视图显示货币转换计算器:

第二个视图显示供用户选择的货币列表。

设置单独的屏幕并在它们之间导航

因为这是我们的第一款具有多个屏幕的赢博体育,所以我需要先列出构建赢博体育的策略。以下是这款赢博体育架构的关键功能。

  1. 我们的一个可组合函数是CurrencyApp ()可组合。这代表了整个赢博体育程序,并设置了在两个屏幕之间移动所需的导航结构。
  2. 设置第一个屏幕CalculatorScreen ()可组合。
  3. 由于计算器屏幕上有一个顶部栏,我们将使用它来帮助导航,因此CalculatorScreen ()支架()包括顶部酒吧。Scaffold的主要内容是计算器()可组合的,实现实际的计算器。
  4. 设置第二个屏幕CurrenciesScreen ()可组合。

我们将详细检查的第一个组件是CurrencyApp()。下面是该组件的代码:

@Composable fun CurrencyApp(modifier: modifier) {val navController = memorbernavcontroller () NavHost(navController,startDestination=“calculator/EUR”){composable(route=“calculator/{code}”,arguments = listOf(navArgument(“code”)){type = NavType。{navStackEntry -> val code = navStackEntry.arguments?.getString("code") CalculatorScreen(code?:“EUR”,toOptions = {navController.navigate("currencies")}, modifier = modifier} composable(route="currencies") {CurrenciesScreen({code: String -> navController.navigate("calculator/$code")}, modifier = modifier)}}

这个组件的主要目的是为我们的赢博体育程序设置导航基础设施。我们通过访问一个NavController(),然后使用那个NavController来设置一个NavHost()组件来实现这一点。NavHost()本质上是一组路由的容器。每条路由都包含一个路由URL和一个末尾的lambda表达式,用来设置将在该路由中显示的组件。

这个例子演示的导航系统的一个有趣的特性是参数化路线的使用。将我们映射到特定屏幕的路由本质上是URL,这些URL允许具有的一个特性是URL中嵌入的参数。在上面的例子中,您可以看到将我们带到计算器屏幕的路由。当我们设置计算器时,我们需要告诉它应该使用哪种货币。为此,我们首先将想要的货币名称嵌入到路由URL中。例如,如果我们想要一个将美元转换为欧元的计算器,我们将使用一个看起来像“calculator/EUR”的路由URL。

当我们使用导航系统导航到特定的路线时,系统将创建一个名为NavStackEntry的对象,并将其推到导航堆栈的顶部。我们可以查询NavStackEntry来获取路由的详细信息,包括嵌入在路由URL中的任何参数。一旦我们从URL中提取了这个参数,我们就可以将它传递给CalculatorScreen()组件,告诉它使用什么货币。下面是负责设置路由,管理路由中嵌入的参数,然后最终创建CalculatorScreen()的代码部分:

composable(route="calculator/{code}", arguments = listOf(navArgument("code")) {type = NavType。{navStackEntry -> val code = navStackEntry.arguments?.getString("code") CalculatorScreen(code?:“EUR”, toOptions = {navController.navigate("currencies")}, modifier = modifier)}

我们在这里设置的另一个路由是一种更简单的路由,它由一个没有参数的简单路由URL和一些直接的代码组成,用于设置与该路由相关的屏幕:

composable(route="currencies") {CurrenciesScreen({code: String -> navController.navigate("calculator/$code")}, modifier = modifier)

}

这里需要注意的最后一个特性是设置NavHost的调用中的startDestination参数。这是一个路由URL,它告诉系统赢博体育启动时要去哪条路由。在本例中,我们希望显示的第一个屏幕是使用欧元的货币计算器集。

currenciessscreen组件

这个赢博体育程序中两个屏幕中比较简单的是CurrenciesScreen()。这个组件被设计用来为用户显示货币列表。

@Composable fun CurrenciesScreen(onClick: (String)->单位,修饰符:修饰符){列(verticalArrangement =安排。中心,modifier = modifier.padding(20.dp)) {Row(horizontalArrangement = Arrangement。中心,modifier = modifier .padding(20.dp)) {Text(“选择货币”)}HorizontalDivider() Column(verticalArrangement =排列。中心,modifier = modifier .padding(20.dp)) {rate .keys. foreach {code -> CurrencyItem(code = code, onClick = onClick)}}}}

这里有一些关于这段代码的注意事项:

汇率= mapOf(欧元至0.9829,英镑至0.8397,日元至135.72,加元至1.3049)

下面是CurrencyItem()组件的代码:

@Composable fun CurrencyItem(code: String, onClick: (String)->Unit) {Text(Text = code, modifier= modifier)。{onClick(code)})}

CurrencyItem()只是一个显示货币代码的Text()组件。我在这里添加的一个特殊特性是一个修饰符,它使Text()组件可单击。clickable修饰符的回调函数调用一个函数,该函数作为CurrencyItem的一个参数传递给CurrencyItem。

如果您从设置货币项的调用向后跟踪代码,您将看到所讨论的函数一直在CurrencyApp()中设置。这个函数定义为

{code: String -> navController.navigate("calculator/$code")}

我们现在拥有的是一个监视用户点击货币代码的系统。当用户单击其中一个代码时,我们使用用户单击的代码触发对上述函数的调用。那个函数反过来告诉navController离开我们所在的屏幕,导航到使用用户刚刚点击的代码将我们带回到计算器屏幕的路线。

CalculatorScreen组件

下面是设置计算器屏幕的组件的代码。

@OptIn(ExperimentalMaterial3Api::class) @Composable fun CalculatorScreen(code: String, toOptions: () -> Unit,modifier: modifier) {Scaffold(topBar = {TopAppBar(title = {Text("Travel Money",)})}, actions = {IconButton(onClick = toOptions) {Icon(imageVector = Icons.Default.)。设置,contentDescription = “设置”)}},)},modifier = modifier. fillmaxsize ()) {innerPadding ->计算器(代码,modifier.padding(innerPadding))}}

关于这个组件,需要注意的最重要的一点是,它不直接设置计算器。相反,该组件要做的第一件事是设置一个Scaffold(),该Scaffold()包含一个顶栏。上下条是需要在多个屏幕之间导航的赢博体育程序的常见功能。通常情况下,这些工具条包含一些图标,用户可以通过点击这些图标来导航到赢博体育程序中的不同屏幕。在这个例子中,Scaffold的顶部工具条包含一个文本标题和一个通过IconButton()实现的动作。单击IconButton触发对toOptions函数的调用,该函数作为参数传递给CalculatorScreen。如果你跟踪代码,你会看到我们传递给该参数的函数是这样的:

{navController.navigate(“货币”)}

因此,当用户点击顶部栏中的图标时,赢博体育程序将导航到显示货币列表的路线。

CalculatorScreen()组件中发生的最后一件事是Scaffold的主体闭包:该闭包设置了Scaffold的主要内容,即Calculator()组件。下面是该组件的代码。

@Composable fun Calculator(code: String,modifier: modifier) {val focusManager = LocalFocusManager。当前val amount = remember {mutableStateOf("100")} val convert = remember {mutableStateOf("%.2f".format(rates[code]!!*100))} fun convert(): Unit {val dollarAmount = amount.value. todoubleornull () if(dollarAmount == null){已转换。value = “未知”}else {val exchangeAmount = rates[code]!!*dollarAmount!!转换。value = "%.2f".format(exchangeAmount)}} Column(horizontalAlignment =对齐方式。centerhorizontal, modifier = modifier. fillmaxsize ()) {Row(horizontalArrangement = Arrangement。开始,verticalalign = align . bottom) {TextField(value = amount. bottom)。value, onValueChange = {newValue: String ->金额。value = newValue}, keyboardOptions = keyboardOptions (imeAction = imeAction . done), keyboardActions = keyboardActions (onDone = {focusManager.clearFocus()})) Spacer(modifier= modifier .width(10.dp)) Text("USD")} Spacer(modifier= modifier .height(20.dp)) Row() {Button(onClick = {convert()}) {Text(" convert ")}} Spacer(modifier= modifier .height(20.dp)) Row() {Text(converded .value) Text(code)}}}

这段代码对于货币转换计算器来说非常简单。这里有两个重要的状态变量,amount和convert。金额是用户将在文本字段中输入的美元金额。要进行货币转换,用户将单击“Convert”按钮。该按钮的回调调用本地convert()函数,该函数将金额中的值转换为其他货币,并存储转换后的状态变量中的结果。