项目档案

更多组件赢博体育

我们的下一个例子是一个赢博体育程序,将演示如何使用一些Jetpack组成组件,我们没有机会在这个过程中覆盖到目前为止。

选项卡导航

这个赢博体育程序演示的第一个新功能是使用选项卡界面的新型导航。在赢博体育程序的底部,你会看到一组三个图标-这些让我们可以通过简单地点击我们想要的屏幕图标轻松地在三个屏幕之间导航。

这个导航结构是在TabApp组件中设置的,它是我们赢博体育的顶层组件:

@Composable fun TabApp() {val navController = memorbernavcontroller () Scaffold(bottomBar = {BottomAppBar(actions = {IconButton(onClick = {navController.navigate("form")}) {Icon(icons . fill .;)编辑,contentDescription = “表单演示”)}IconButton(onClick = {navController.navigate("dialog")}) {Icon(icons . fill . .)检查,contentDescription = "Dialog Demo")} IconButton(onClick = {navController.navigate("photo“)}) {Icon(icons . fill . ”AccountBox, contentDescription =" Photo Demo")}})}, modifier = modifier . fillmaxsize ()) {innerPadding -> NavHost(navController,startDestination="form") {composable(route="form") {FormScreen(modifier = modifier .padding(innerPadding))} composable(route="dialog") {DialogScreen(modifier = modifier .padding(innerPadding))} composable(route=" Photo ") {PhotoScreen(modifier = modifier .padding(innerPadding)))}}}}

这里的神奇之处在于,它结合了一个Scaffold、一个BottomAppBar和一个NavHost来设置我们的导航路线。

BottomAppBar有一个actions部分,其中包含三个iconbutton的列表。每个IconButton的onClick参数包含代码,告诉navController导航到适当的路由。

表单演示

在我们的示例赢博体育程序的三个屏幕中,第一个屏幕演示了一些我们还没有机会使用的输入组件的使用。

下面是该屏幕的代码:

@Composable fun FormScreen(modifier: modifier) {val toggleState = remember {mutableStateOf(false)} val meals = listOf(“早餐”,“午餐”,“晚餐”)val favoriteMeal = remember {mutableStateOf(meals[1])} val colors = listOf(“红色”,“绿色”,“蓝色”)val favoriteColor = remember {mutableStateOf(colors[1])} Column(verticalArrangement = Arrangement。居中,horizontalAlignment =对齐。centerhorizontal, modifier = modifier. fillmaxsize ().padding(10.dp)) {Card() {Column(modifier = modifier. padding(10.dp)) {Row(horizontalArrangement = Arrangement。开始,垂直对齐=对齐。{Text("Prefer this:") spacing (modifier = modifier .width(10.dp)) Switch(checked = toggleState.)值,onCheckedChange = {toggleState。value = it})} if (toggleState.value) Text("You prefer this.") else Text("You prefer that.")}} Spacer(modifier= modifier .height(10.dp)) Card() {Column(modifier = modifier .padding(10.dp)) {Row(horizontalArrangement = Arrangement.)开始,垂直对齐=对齐。Text(“你最喜欢的一餐是什么?”)Spacer(modifier = modifier .width(10.dp)) TextMenu(meals,meals[1],{favoriteMeal. "value = it})} Text(“你最喜欢的一餐是${favoritemale .value}.”)}} Spacer(modifier= modifier .height(10.dp)) Card() {Column(modifier .padding(10.dp). selectablegroup ()) {Text(“你最喜欢的颜色是什么?”)颜色。forEach {color ->行(修改符)。selectable(selected = (color == favoriteColor.value), onClick = {favoriteColor.value。value = color}, role =角色。padding(horizontal = 16.dp), verticalAlignment = align。{RadioButton(selected = (color == favoriteColor.value), onClick = null) Text(Text = color, style = MaterialTheme.typography)bodyMedium, modifier = modifier。padding(start = 16.dp)}} Text(“您选择了${favoriteccolor .value} ”)}}}}

这里要注意的第一件事是Card()组件的使用,它充当屏幕不同部分的容器。

在赢博体育这些代码中,您将看到三个新用户界面组件的示例:Switch()、下拉菜单和RadioButton()。

Switch()实现了一个简单的双位置拨动开关。为了使用它,我们将它链接到一个简单的布尔状态变量toggleState:

Switch(checked = toggleState)。值,onCheckedChange = {toggleState。Value = it})

因为下拉菜单在Android中很难实现,所以我将下拉菜单的代码分解为它自己的组件:

@Composable fun TextMenu(选择:列表<String>,默认:字符串,onChoice: (String)->单位){val expanded = remember {mutableStateOf(false)} val selected = remember {mutableStateOf(默认)}Column() {Row(modifier = modifier)。background(color = MaterialTheme.colorScheme.background).padding(5.dp) .clickable(onClick ={已扩展。Value = !展开。{Text(selected.value) Icon(imageVector = Icons.Default. value)MoreVert, contentDescription = "More")}下拉菜单(expanded =展开。值,on驳回请求={扩展。Value = false}){选项。forEach{选择-> DropdownMenuItem(文本={文本(选择)},onClick ={选择。价值=扩大的选择。value = false onChoice(choice)})}}}}

这个组件的目的是设置一个下拉菜单,显示一个字符串列表作为可能的选择。此外,调用者必须指出在开始时选择了哪个选项,以及一个回调函数,当用户从菜单中做出新选择时,我们将调用该函数。

下拉菜单是两个部分的组合。第一部分是一个Text()元素和一个Icon(),显示用户当前的选择。这些将在屏幕上可见。当用户单击第一部分时,第二部分(即完整的选择菜单)就会出现在屏幕上。

菜单是通过DropdownMenu()组件实现的。为了控制菜单是否显示,我们使用了一个状态变量expanded。组件的主体是我们在通常的forEach结构中为菜单设置选项列表的地方。我们通过DropdownMenuItem()组件设置菜单中的每个选项,该组件允许为选项配置文本,并在用户单击项时调用回调。

注意,回调中的代码更新了所选状态变量,该变量控制组件的第一部分显示哪些文本,然后调用onChoice()回调函数,该函数随新选择传递给我们。

这个屏幕演示的最后一件事是设置单选按钮并将它们放入一个单选组。在一个单选组中,一次只能选中一个单选按钮。成功设置赢博体育这些是三个组件之间复杂的相互作用:绑定单选组的Column()、组中的条目的Row()和RadioButton组件本身。以下是代码的相关部分:

列(Modifier.padding(10.dp). selectablegroup ()) {Text(“你最喜欢的颜色是什么?”)颜色。forEach {color ->行(修改符)。selectable(selected = (color == favoriteColor.value), onClick = {favoriteColor.value。value = color}, role =角色。RadioButton)。padding(horizontal = 16.dp), verticalalign = align。{RadioButton(selected = (color == favoriteColor.value), onClick = null) Text(Text = color, style = MaterialTheme.typography)bodyMedium, modifier = modifier。padding(start = 16.dp)}} Text(“您选择了${favoriteColor.value} ”)}

这里我们要做的第一件特殊的事情是在列上使用一个特殊的selectableGroup()修饰符。这允许列作为其内部单选按钮的组。接下来,我们将每个单选按钮与其文本标签放在一行中,并对该行赢博体育一个特殊的selectable()修饰符。该修饰符有三个参数,它们决定一行是否被选中、当用户单击该行时要做什么,以及一个角色参数,它指定我们正在使用单选按钮。最后,RadioButton本身只需要一些逻辑来确定是在选中状态下将自己绘制为一个填充的圆圈,还是在未选中状态下将自己绘制为一个空圆圈。

对话框

赢博体育程序中的第二个屏幕演示了警报和对话框的使用。

下面是这个屏幕的代码:

@Composable fun DialogScreen(modifier: modifier) {val done = remember {mutableStateOf(false)} val openAlert = remember {mutableStateOf(false)} val colors = listOf(“Red”,“Green”,“Blue”)val favoriteColor = remember {mutableStateOf(colors[0])} val openDialog = remember {mutableStateOf(false)} Column(verticalArrangement = Arrangement。居中,horizontalAlignment =对齐。centerhorizontal, modifier = modifier. fillmaxsize ().padding(10.dp)) {if(done.value) {Text("You did it.“)} else {Button(onClick = {openAlert. ”value = true}) {Text("Do It!")}} if (openAlert.value) {AlertDialog(onDismissRequest = {openAlert.value)}value = false}, title = {Text(Text = "Are you sure?")}, Text = {Text(Text = "Are you sure you want to do it?“)}, confirmButton = {TextButton(onClick = {openAlert. ”Value = false done。value = true}) {Text("Confirm")}}, replybutton = {TextButton(onClick = {openAlert. info})Text(modifier = modifier .height(20.dp)) Text(“你最喜欢的颜色是${favoriteColor.value} ”) Button(onClick = {openDialog. value})value = true}) {Text("Change it!")} if(openDialog.value) {DialogWithChoice(choices = colors, onConfirmation = {favoriteColor。value = it openDialog。value = false}, on遣散请求= {openDialog. value = false}Value = false})}}

这里要关注的两个组件是AlertDialog()和DialogWithChoice()。AlertDialog()是一个内置组件,我们将调用它来发出警报,而第二个组件是一个我们将为其编写代码以发出对话框的组件。

在处理警报和对话框时,我们需要的第一件事是状态变量,用于控制这些东西何时出现在屏幕上。在本例中,状态变量openAlert控制警报的外观,而openDialog控制是否显示对话框。

警报和对话框都是模态组件,这意味着当它们出现在屏幕上时,它们会阻止用户与屏幕上的任何其他组件进行交互,直到它们被解除。

本例中的警报链接到“Do It!”按钮。当用户单击该按钮时,我们将openAlert状态变量翻转为true,这反过来导致警报显示:

下面是警报组件的特定代码:

AlertDialog(on遣散请求= {openAlert.})value = false}, title = {Text(Text = "Are you sure?")}, Text = {Text(Text = "Are you sure you want to do it?“)}, confirmButton = {TextButton(onClick = {openAlert. ”Value = false done。value = true}) {Text("Confirm")}}, replybutton = {TextButton(onClick = {openAlert. info})value = false}) {Text(“解散”)}})

一个简单的警报有一个标题、一些文本和几个按钮。正如您在这里看到的,按钮逻辑使警报消失,并且在确认按钮的情况下,还更新屏幕中的另一个键状态变量。

对话框更加复杂。这样做的原因是,除了简单地获得是/否响应之外,对话框还用于从用户那里收集其他信息。这将需要使用额外的用户界面元素来收集该信息。我们通常通过为对话框构建我们自己的组件来设置对话框——这就是我在这里所做的。下面是我在这里设置的自定义对话框组件的代码:

@Composable fun DialogWithChoice(choices: List<String>, onConfirmation: (String) -> Unit, on遣散请求:()-> Unit) {val selected = remember {mutableStateOf(choices[0])} Dialog(on遣散请求= {on遣散请求()}){Card(modifier = modifier .padding(16.dp), shape = RoundedCornerShape(16.dp),) {Column(modifier = modifier, verticalArrangement = Arrangement。Center) {Text(Text = “做一个选择”,modifier = modifier .padding(16.dp),) choices。forEach{选择->行(修改符。selectable(selected = (choice == selected.value), onClick = {selected。value = choice}, role = role。padding(horizontal = 16.dp), verticalAlignment = align。{RadioButton(selected = (choice == selected.value), onClick = null) Text(Text = choice, style = MaterialTheme.typography)bodyMedium, modifier = modifier。padding(start = 16.dp)}} Row(modifier = modifier . fillmaxwidth (), horizontalArrangement =排列。Center,) {TextButton(onClick = {onDismissRequest()}, modifier = modifier .padding(8.dp),) {Text(“驳回”)}TextButton(onClick = {onConfirmation(selected.value)}, modifier = modifier .padding(8.dp),) {Text(“确认”)}}}}}}

这里最重要的事情是Dialog()组件的使用。该组件有一个主体部分,我们在其中设置对话框的完整用户界面。在本例中,这是一个Card(),它包含了我们需要的一切,包括一个文本提示符、一组表示选项的单选按钮和底部的按钮。

对话框链接到“Change It!”按钮。当用户单击该按钮时,我们翻转showDialog变量的状态,从而导致对话框出现。

我努力使DialogWithChoice()组件的代码具有一定的通用性,以便您可以在其他设置中重用该代码。定义组件的函数接受三个参数:一个字符串列表,列出供用户选择的选项,以及两个回调函数,当用户关闭对话框或做出选择并确认时调用。您可以查看调用该组件的DialogScreen()中的代码,了解我是如何使用这三个参数的。特别是,您应该仔细看看我是如何设置传递给DialogWithChoice()的回调函数的。

处理照片

演示赢博体育程序中的最后一个屏幕演示了如何使用照片选择器和图像来显示图片。

下面是这个屏幕的代码:

@Composable fun PhotoScreen(modifier: modifier) {val selectedImage = remember {mutableStateOf<Uri?>(null)} val photoPickerLauncher = rememberLauncherForActivityResult(contract = ActivityResultContracts.PickVisualMedia(), onResult = {selectedImage。) fun launchPhotoPicker() {photoPickerLauncher. value = it}launch(PickVisualMediaRequest(activityresultcontractions . pickvisualmedia . imageonly))} Column(modifier = modifier . fillmaxsize (), horizontalAlignment = Alignment。centerhorizontal) {Spacer(modifier = modifier .height(30.dp)) Button(onClick = {launchPhotoPicker()}) {Text("Pick a photo.")} if(selectedImage.)= null) {AsyncImage(model = selecteimage .value!!, contentDescription = null, modifier = modifier . fillmaxwidth (), contentScale = contentScale。Fit)}}

组件顶部的两个状态变量和函数为挑选照片设置了必要的基础结构。为了挑选一张照片,我们使用一个启动器,它被存储在photoPickerLauncher状态变量中。当我们调用启动器并且用户选择要处理的照片时,我们将返回一个可选的Uri对象,该对象指向存储所选图像的文件。

为了显示选中的图像,我们将使用AsyncImage()组件。这个组件不是Jetpack Compose的一部分——它来自Coil库。为了在我们的项目中包含Coil库,我们必须添加以下依赖项:

实现(“io.coil-kt: coil-compose: 2.5.0”)

有关更多组件的信息

在本例中,我尝试扩展您所知道的组件集,为您提供用于即将进行的项目的附加工具。

如果您想了解更多关于可用组件的信息,我可以推荐composables.com网站,该网站概述了大量可用组件,这些组件要么是Jetpack Compose本身的一部分,要么是附加组件的材料库。