一. 构建基础布局
什么是界面UI?
应用的界面 (UI) 就是您在屏幕上所看到的内容(文本、图片、按钮和许多其他类型的元素)及其在屏幕上的布局方式。它既是应用向用户显示内容的方式,也是用户与应用展开互动的载体
1.1. Jetpack Compose介绍
什么是Jetpack Compose?
Jetpack Compose 是用于构建 Android 界面的新款工具包。Compose 使用更少的代码、强大的工具和直观的 Kotlin 功能,可以帮助您简化并加快 Android 界面开发。借助 Compose,您可以通过定义一组函数来构建界面,这些函数称为可组合函数,它们会接受数据并描述界面元素。
1.1.1. 可组合函数
在 Compose 中,可组合函数是界面的基本构建块。可组合函数:
- 描述界面中的某一部分。
- 不会返回任何内容。
- 接受一些输入并生成屏幕上显示的内容。
@ComposablefunGreeting(name:String){Text(text="Hello$name!")}可组合函数带有@Composable注解。所有可组合函数都必须带有此注解。此注解可告知Compose编译器:此函数用于将数据转换为界面。请注意,编译器是一种特殊的程序,它会接受您编写的代码,逐行查看,然后将其转换成计算机可以理解的指令(机器语言)。
关于可组合函数的几点说明:
- Jetpack Compose 是围绕可组合函数构建的。这些函数可让您以程序化方式定义应用的界面,只需描述应用界面的外观,而不必关注界面的构建过程。
如需创建可组合函数,只需将 @Composable 注解添加到函数名称中即可 - 可组合函数可以接受一些实参,用来让应用逻辑描述或修改界面。在本例中,界面元素接受一个 String,以便在问候用户时称呼姓名。
1.1.2. 注释
注解是用于在代码中附加额外信息的方式。此类信息可以帮助 Jetpack Compose 编译器等工具和其他开发者理解应用的代码。
若要应用注解,只需在您要注解的声明开头为其名称(注解)添加@字符作为前缀即可。您可以为包括属性、函数和类在内的不同代码元素添加注解。
下图是一个带有注解的函数示例:
以下代码段中包含一些带有注解的属性示例。在后续开发中,您将用到这些属性。
// Example code, do not copy it over@JsonvalimgSrcUrl:String@VolatileprivatevarINSTANCE:AppDatabase?=null1.1.3. 带形参/不带形参的注解
注解可以接受形参。形参可以为处理它们的工具提供额外信息。以下是带形参和不带形参的 @Preview 注解的一些示例
不带形参的注解:
带形参的注解:
带有预览标题的注解:
您可以向注解传递多个实参,如下所示:
## 1.2. 更改字体大小
可缩放像素可缩放像素 (SP)是字体大小的度量单位。Android 应用中的界面元素使用两种不同的度量单位:一种是您稍后将为布局使用的密度无关像素 (DP),另一种就是可缩放像素 (SP)。默认情况下,SP 单位与 DP 单位大小相同,但前者的大小会根据用户在手机设置下的首选文本大小进行调整。
- 在
MainActivity.kt文件中,滚动到GreetingText()函数中的Text()可组合项。 - 向
Text()函数传递fontSize实参作为第二个具名实参,并将其值设为100.sp。
@ComposablefunGreetingText(message:String,modifier:Modifier=Modifier){// 设置字体大小和行高Text(message,fontSize=100.sp,lineHeight=116.sp)}效果:
我们还可以再添加一个文本:
@ComposablefunGreetingText(message:String,from:String,modifier:Modifier=Modifier){Text(from,fontSize=36.sp)Text(message,fontSize=100.sp,lineHeight=116.sp)}@Preview(showBackground=true)@ComposablefunBirthdayCardPreview(){GreetingText(message="Happy Birthday Sam!","From Emma")}
一个可组合函数可能会描述多个界面元素。不过,如果您未提供有关如何排列这些元素的指导,Compose 可能会以您不喜欢的方式排列它们。例如,上面的代码生成了两个相互重叠的文本元素,因为您没有提供有关如何排列这两个可组合项的指导。
1.3. 文本的排列方式(行/列)
界面层次结构基于包含机制,意即一个组件可以包含一个或多个组件,有时会用“父级”和“子级”这两个词来表述。这种说法是指,父界面元素包含子界面元素,而子界面元素还可以继续包含子界面元素。在此部分中,您将了解可用作父界面元素的Column、Row 和 Box 可组合项。
Compose中的3 个基本标准布局元素是Column、Row 和 Box可组合项。后面会介绍Box
Column、Row 和 Box 都是接受可组合内容作为参数的可组合函数,因此您可以在这些布局元素内放置项目。例如,Row 可组合项中的各个子元素彼此相邻地水平放置成一行。
@ComposablefunGreetingText(message:String,from:String,modifier:Modifier=Modifier){Row{Text(from,fontSize=36.sp)Text(message,fontSize=36.sp,lineHeight=36.sp)}}将内容排成一列:
@ComposablefunGreetingText(message:String,from:String,modifier:Modifier=Modifier){Column{Text(from,fontSize=36.sp)Text(message,fontSize=36.sp,lineHeight=36.sp)}}1.4. 尾随lambda语法
请注意,在上一个代码段中,Row 可组合函数中使用的是花括号而不是圆括号。这称为尾随 Lambda 语法。稍后会详细介绍 lambda 和尾随 lambda 语法。现在,您只需要熟悉这个常用的 Compose 语法。
当最后一个形参是函数时,Kotlin 提供了一种特殊语法来将函数作为形参传递给函数
将函数作为形参传递时,您可以使用尾随 lambda 语法。您可以将函数放在圆括号外部的大括号中,而不是放在圆括号内。这是 Compose 中的一种常见且推荐的做法,因此您需要熟悉代码的格式。
例如,Row() 可组合函数中的最后一个形参是 content 形参,它是一个描述子界面元素的函数。假设您想要创建一个包含三个文本元素的行。以下代码行得通,但如果为尾随 lambda 使用具名形参,则非常麻烦:
Row(content={Text("Some text")Text("Some more text")Text("Last text")})由于 content 形参是函数签名中的最后一个形参,并且您要将其值作为 lambda 表达式传递,因此您可以移除 content 形参和括号,如下所示:
Row{Text("Some text")Text("Some more text")Text("Last text")}1.5 将内容居中
- 如需在屏幕中心对齐问候语,请添加一个名为
verticalArrangement的形参,并将其设置为Arrangement.Center。
@ComposablefunGreetingText(message:String,from:String,modifier:Modifier=Modifier){Column(verticalArrangement=Arrangement.Center,modifier=modifier){Text(from,fontSize=36.sp,modifier=Modifier.padding(16.dp)// Compose 提供 align 修饰符来单独控制子级可组合项的位置,使其不受父布局强制执行的对齐布局规则的约束。这里是单独制定该text的排列方式.align(alignment=Alignment.End))Text(message,fontSize=36.sp,lineHeight=36.sp,textAlign=TextAlign.Center)}}1.6. 添加图片
若要在应用中显示图片,需要有一个显示位置。就像使用 Text 可组合项显示文本一样,可以使用 Image 可组合项来显示图片。
通过添加可组合函数来添加图片
- 在
MainActivity.kt文件中,在GreetingText()函数后面添加一个GreetingImage()可组合函数。 - 向
GreetingImage()函数传递两个String形参:一个名为 message,用于添加生日祝福语,另一个名为 from,用于添加签名。 - 每个可组合函数都应接受一个可选的
Modifier形参。修饰符用于控制界面元素在其父布局中的放置、显示或行为方式。在 GreetingImage() 可组合函数中添加另一个形参。
@ComposablefunGreetingImage(message:String,from:String,modifier:Modifier=Modifier){}1.6.1 Jetpack Compose中的资源
资源是指代码使用的附加文件和静态内容,例如位图、界面字符串、动画说明等。
您应该始终将应用资源(如图片和字符串)与代码分隔开,以便能够独立地维护这些资源。在运行时,Android 会根据当前配置使用合适的资源。例如,您可能想根据屏幕尺寸提供不同的界面布局,或根据语言设置提供不同的字符串
资源分组
您应始终将每种类型的资源放在项目的res/目录下的相应子目录中。例如,以下是一个简单项目的文件层次结构:
MyProject/src/MyActivity.kt res/drawable/graphic.png mipmap/icon.png values/strings.xml在此示例中,res/目录中包含存储在不同子目录中的所有资源,其中包括存储图片资源的 drawable/ 目录、存储启动器图标的 mipmap/目录和存储字符串资源的 values/目录。
访问资源
Jetpack Compose 可以访问您的Android 项目中定义的资源。可以使用在项目的R 类中生成的资源 ID 访问资源。
R 类是Android自动生成的类,其中包含了项目中所有资源的 ID。在大多数情况下,资源 ID 与文件名相同。例如,可以使用以下代码访问上面的文件层次结构中的图片:
R.drawable.graphic1.6.2 显示图片
- 在
GreetingImage()函数中,声明val属性并将其命名为image。 - 通过传入
androidtest资源来调用painterResource()函数。将返回值分配给image变量。
valimage=painterResource(R.drawable.androidtest)// painterResource() 函数会加载可绘制图片资源,并将资源 ID(在本例中为 R.drawable.androidparty)作为实参- 调用
painterResource()函数后,添加Image可组合函数,然后传入image作为painter的具名实参。
@ComposablefunGreetingImage(message:String,from:String,modifier:Modifier=Modifier){valimage=painterResource(R.drawable.androidtest)Image(painter=image)}报错如下:
解决方案:
Image(painter=image,// 将图片的 contentDescription 实参设为 null,以便 TalkBack 跳过 Image 可组合函数。contentDescription=null// 无障碍描述)1.7. 添加盒子布局(Box)
Box 布局是 Compose 中的标准布局元素之一。使用 Box 布局可将元素堆叠在一起。Box 布局还可用于配置它所包含的元素的特定对齐方式。
- 在
GreetingImage()函数中,添加围绕 Image 可组合项的 Box 可组合项,如下所示 - 然后 在GreetingImage函数中调用GreetingText函数
@ComposablefunGreetingImage(message:String,from:String,modifier:Modifier=Modifier){valimage=painterResource(R.drawable.androidtest)Box(modifier){Image(painter=image,contentDescription=null)GreetingText(message,from,Modifier.fillMaxSize().padding(8.dp))}}1.8. 调整图片大小
Image(painter=image,contentDescription=null,// 设置图片的缩放方式contentScale=ContentScale.Crop,// 使图片充满Box(父盒子)modifier=Modifier.fillMaxSize(),// 设置图片的透明度alpha=0.5f)最终效果:
1.9 Spacer - 间距
@ComposablefunSpacerDemo(){Column(modifier=Modifier.padding(16.dp)){Text("标题",fontSize=20.sp,fontWeight=FontWeight.Bold)// 增加间距组件Spacer(modifier=Modifier.height(8.dp))// 标题和内容之间相距8.dpText("这是文字内容",fontSize=14.sp,color=Color.Gray)}}- Spacer: 是手动在两个元素之间插入间距,更灵活
- spacedBy:spacedBy(8.dp)是在Column/Row参数中设置,自动给所有子元素加间距。
2.0 weight - 按比例分配
@ComposablefunWeightDemo(){Column(modifier=Modifier.fillMaxWidth().background(Color.Green)){Row(modifier=Modifier.fillMaxWidth().height(40.dp)){Box(modifier=Modifier.weight(1f).fillMaxSize().background(Color.Red))Box(modifier=Modifier.weight(1f).fillMaxSize().background(Color.Green))Box(modifier=Modifier.weight(1f).fillMaxSize().background(Color.Blue))}}}