本文是根据官方文档学习 作笔记记录
目录
- Composable functions (可组合函数)
- Layouts(文本,cloumn,图片,布置布局)
- Material Design (Color(颜色),Typography(排版),Shape(形状),启用深色主题)
- Lists and animations(列表和动画)
- 领会的一些使用技巧
Jetpack Compose 是 Google 推出的 用来构建 Android 用户界面的工具包,采用的是声明式的方法。(如果你接触过 Flutter ,会有似曾相识的感觉。)对于本文的学习,如果你有 Kotlin 的开发基础, 一点Android 应用开发的知识,会轻松一点。
Composable functions
Compose 可组合函数是 Jetpack Compose 的基本构建块,用于定义UI 组件。
下面是一个简单示例 Greeting
widget ,接收 String
参数 并通过 Text
widget 显示出来。
kotlin
// ...
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Greeting("AndroidDeveloper")
}
}
}
@Composable
fun Greeting(name: String) {
Text("Hello $name!")
}
关于此函数,有几点需要注意。
- @Composable 注解。这个注解告诉编译器,这个函数的目的是将数据转换为用户界面。
- 带有此注解的函数也被称为可组合函数,简称可组合函数。这些函数是 Compose 中用户界面的构件。添加此注解非常简单快捷,可帮助您将用户界面组织成一个可重复使用的元素库
- 此函数接收数据, 可组合函数可接收参数,用于界面描述。
- 此函数不返回任何内容 (但它会返回
Unit
),声明式命名组件,用于描述屏幕状态而非构建界面widget。
在 Android Studio 预览你的函数
@Preview
注解 可帮助你实时预览可组合函数,无需构建应用程序并安装在Android 设备或者浏览器。 该注释必须用在不接受参数的可组合函数,因此无法直接预览 Greeting
的功能,需要创建一个 DefaultPreview
,传入参数去调用 Greeting
。
kotlin
@Composable
fun Greeting(name: String) {
Text("Hello $name!")
}
@Preview(showBackground = true,widthDp = 360, heightDp = 360)
@Composable
fun DefaultPreview() {
Greeting(" Developer!")
}
@Preview
注解中各项配置可设置,供你预览效果。
Layouts
在绘制页面时,UI元素是分层的, 元素包裹在其他元素中,(各种Layout,View 的嵌套),而在Compose 中,我们可以通过其他组合函数调用可组合函数来构建UI层次结构。
到这里,我们已经知道 Compose 可组合函数 和 预览的用法了,接下来 是学会如何使用布局去完善效果。
这里我和官方文档一样 ,使用消息列表 这个样例来学习。
添加多个文本
kotlin
class SecondActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MessageCard(Message("Android", "Jetpack Compose"))
}
}
}
data class Message(val author: String, val body: String)
@Composable
fun MessageCard(msg: Message) {
Text(text = msg.author)
Text(text = msg.body)
}
从上图效果,我们创建的两个 Text
元素,是会重叠在一起,原因是我们未提供有关如何排列文本元素的信息。
使用 Column
Column
函数 可以垂直排列 其布局内元素。 你也可以使用 Row
,Box
去实现想要的效果。
kotlin
@Composable
fun MessageCard(msg: Message) {
Column() {
Text(text = msg.author)
Text(text = msg.body)
}
}
添加Image
kotlin
@Composable
fun MessageCard(msg: Message) {
Row() {
Image(painter = painterResource(id = R.drawable.cat), contentDescription = "Contact profile picture")
Column() {
Text(text = msg.author)
Text(text = msg.body)
}
}
}
预览效果
现在看到的效果, 图片太大了, 间距也没有。这时候就需要就需要 Modifier
,点进Row 的源码可以看到默认参数是有 Modifier
,它的用途类似 将Android Layout 中的配置属性,做了一个集合,详细的各位可以看源码 或者文档, 我这里就不细说了。
kotlin
@Composable
fun MessageCard(msg: Message) {
Row() {
Image(
painter = painterResource(id = R.drawable.cat),
contentDescription = null,
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
)
Spacer(modifier = Modifier.width(8.dp))
Column() {
Text(text = msg.author)
Spacer(modifier = Modifier.height(4.dp))
Text(text = msg.body)
}
}
}
这个效果比之前的好点了, Modifier
可玩性很高,更多功能各位可以自己去发掘。
Material Design
Compose 当然也是支持 Material Design 原则的, 它许多页面元素都原生支持 Material Design ,这里我使用了 项目中创建的Material
主题 和 Surface
来修改了 MessageCard 的外观 。
Material Design 是围绕 Color
、Typography
、Shape
这三大要素构建的。下面的代码将围绕这三大元素修改。
- 预览效果 & 主题文件位置
Color
使用 MaterialTheme.colors ,可用封装在主题的颜色来设置效果。
kotlin
@Composable
fun MessageCard(msg: Message) {
Row() {
Image(
painter = painterResource(id = R.drawable.cat),
contentDescription = null,
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
**.border(1.5.dp, MaterialTheme.colors.secondary, CircleShape)**
)
Spacer(modifier = Modifier.width(8.dp))
Column() {
Text(text = msg.author, **color = MaterialTheme.colors.secondaryVariant**)
Spacer(modifier = Modifier.height(4.dp))
Text(text = msg.body)
}
}
}
- 预览效果
Typography
MaterialTheme.typography.*
这里用在 text的 style 中
Shape
这块是我作为UI仔最喜欢的地方了,(整点花里胡哨的) 兄弟们,你看看这效果,就一句代码 !!就一句!! 不用写shape.xml , 不用盲猜了, 还能预览 !! 赶紧上号更新呀!
这里设置了shape
的大小(有三种尺寸选择,我们大部分的需求都能满足), 阴影加了1dp ,对了 ,各位发现没 ,直接是1.dp
kotlin
@Composable
fun MessageCard(msg: Message) {
Row() {
Image(
painter = painterResource(id = R.drawable.cat),
contentDescription = null,
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.border(1.5.dp, MaterialTheme.colors.secondary, CircleShape)
)
Spacer(modifier = Modifier.width(8.dp))
Column() {
Text(
text = msg.author,
color = MaterialTheme.colors.secondary,
style = MaterialTheme.typography.subtitle2
)
Spacer(modifier = Modifier.height(4.dp))
**Surface(shape = MaterialTheme.shapes.medium, elevation = 1.dp)** {
Text(text = msg.body,modifier = Modifier.padding(all = 4.dp) , style = MaterialTheme.typography.body2)
}
}
}
深色主题
因为Jetpack Compose 默认支持 Material Design ,所以系统会自动适应深色背景
添加新的预览注解并启用夜间模式。
kotlin
@Preview(name = "Light Mode")
@Preview(
uiMode = Configuration.UI_MODE_NIGHT_YES,
showBackground = true,
name = "Dark Mode"
)
@Preview(showBackground = true)
@Composable
fun PreviewMessageCard() {
MySootheTheme {
Surface {
MessageCard(
msg = Message("Lexi", "Hey, Look at this cute cat, it's so so lovely!")
)
}
}
}
这里浅色和深色主题的颜色选项是在 IDE 生成 的 Theme.kt
中定义的。
Lists and animations
来到我们常用的列表和动画了, 跟着官方文档学完后,我觉得这代码写起来真的变轻松了🥺 。
创建消息列表
这里的子项items 接收 传递 过来的参数list,lambda 省略了 遍历list这块代码 ,这里的message 是自定义命名的,LazyColumn 顾名思义只加载屏幕上显示的内容,对于长列表布局会更高效。
保存状态 & 添加动画
到这里,消息列表的雏形就有了 ,在这块内容要做的是把一些过长的内容收起来,加上动画效果,把跟踪消息是否展开储存为本地界面状态。 需要用到 **remember**
和 mutableStateOf
函数 。
**remember
** 可将本地状态存储在内存中,并把跟踪的值的变化传递给 mutableStateOf
。这个值的更新,系统会自动重新绘制使用此状态的可组合项(及其子项),这叫重组,可以看下链接的官方解释。
通过使用 Compose 的状态 API(如 remember
和 mutableStateOf
),系统会在状态发生任何变化时自动更新界面。
kotlin
@Composable
fun MessageCard(msg: Message) {
Row(modifier = Modifier.padding(all = 8.dp)) {
Image(
painter = painterResource(id = R.drawable.cat),
contentDescription = null,
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.border(1.5.dp, MaterialTheme.colors.secondary, CircleShape)
)
Spacer(modifier = Modifier.width(8.dp))
**var isExtended by remember { mutableStateOf(false) }**
Column(**Modifier.clickable { isExtended = !isExtended }**) {
Text(
text = msg.author,
color = MaterialTheme.colors.secondary,
style = MaterialTheme.typography.subtitle2
)
Spacer(modifier = Modifier.height(4.dp))
Surface(shape = MaterialTheme.shapes.medium, elevation = 1.dp) {
Text(
text = msg.body,
modifier = Modifier.padding(all = 4.dp),
style = MaterialTheme.typography.body2,
**maxLines = if (isExtended) Int.MAX_VALUE else 1**
)
}
}
}
}
- 预览效果
根据 isExpanded 跟踪的状态,修改展开和 收起来消息的背景颜色 (使用 MaterialTheme.colors 的两种颜色 )。 animateContentSize
消息容器的动画效果。
kotlin
@Composable
fun MessageCard(msg: Message) {
Row(modifier = Modifier.padding(all = 8.dp)) {
Image(
painter = painterResource(id = R.drawable.cat),
contentDescription = null,
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.border(1.5.dp, MaterialTheme.colors.secondary, CircleShape)
)
Spacer(modifier = Modifier.width(8.dp))
var isExpanded by remember { mutableStateOf(false) }
v**al surfaceColor by animateColorAsState(
if (isExpanded) MaterialTheme.colors.primary else MaterialTheme.colors.surface,
)**
Column(Modifier.clickable { isExpanded = !isExpanded }) {
Text(
text = msg.author,
color = MaterialTheme.colors.secondary,
style = MaterialTheme.typography.subtitle2
)
Spacer(modifier = Modifier.height(4.dp))
Surface(shape = MaterialTheme.shapes.medium, **color = surfaceColor**, elevation = 1.dp) {
Text(
text = msg.body,
modifier = Modifier.padding(all = 4.dp),
style = MaterialTheme.typography.body2,
maxLines = if (isExpanded) Int.MAX_VALUE else 1
)
}
}
}
}
- 最终加上 背景色的动态效果
以下是您目前为止所学的内容,所有内容只需不到 100 行代码!:
- 定义可组合函数
- 在可组合项中添加不同的元素
- 使用布局可组合项构建界面组件
- 使用修饰符扩展可组合项 Modifiers
- 创建高效列表
- 跟踪状态以及修改状态
- 在可组合项上添加用户互动
- 在展开消息时显示动画效果
改进的技巧,发现了比我讲得好的博主,我这里就不写了,分享给大家。