Jetpack Compose 是个啥?为啥要学它?
谷歌对 Jetpack Compose 的定义:
Jetpack Compose 是推荐用于构建原生 Android 界面的新工具包。它可简化并加速 Android 上的界面开发,运用更少的代码、强壮的工具和直观的 Kotlin API,快速打造生动而精彩的运用。
提取关键词:界面开发新工具包、简化并加速界面开发、Kotlin API。
对于大部分Android项目来说,假如根底库(如网络库、hybird、图片加载、热修复库等)现已搭好,那么平常大部分时刻便是跟 UI界面、需求逻辑 打交道了,而谷歌供给的 Jetpack Compose 正好是加速界面开发的工具包。
就跟魂斗罗里的子弹类型似的,运用一般子弹(XML办法)也能够通关,可是相比之下耗时更长;而换成超级子弹(Jetpack Compose)体会就不相同了,耗时更少,而且游戏体会更爽!
指令式UI vs 声明式UI
长期以来,Android 视图层次结构一直能够表明为界面 widget 树。最常见的界面更新办法是运用 findViewById()
等函数遍历树,并经过调用 button.setText(String)、container.addChild(View) 或 img.setImageBitmap(Bitmap) 等办法更改节点。这些办法会改变 widget 的内部状况,这种手动更新UI的办法便是指令式UI。
在过去的几年中,整个行业已开始转向声明性界面模型,该模型大大简化了与构建和更新界面相关的工程使命。该技术的作业原理是在概念上从头开始从头生成整个屏幕,然后仅履行必要的更改。此办法可避免手动更新有状况视图层次结构的复杂性。Compose 便是一个声明式UI结构。
Jetpack Compose要学起来了?
很遗憾,Jetpack Compose 的确要学起来了(快起来,你还能学!哈哈…),跟着Jetpack Compose 版别的不断迭代,API 逐渐安稳了,功能也越来越好了。
-
更少的代码:编写代码只需要采用
Kotlin
,而不必拆分成Kotlin + XML
办法了。 - 直观:只需描绘界面,Compose会负责处理剩下作业。运用状况变化时,界面自动更新。
- 加速开发:View 与 Compose 之间能够彼此调用,兼容现有的所有代码。借助AS能够实时预览界面,轻松履行界面查看。
- 功能强壮:直接访问Android API,内置对Material Design、主题、动画等的支撑。
Jetpack Compose vs Flutter
- Jetpack Compose的目的是为了进步 Android 原生的 UI 开发功率!声明式UI现已成为干流的开发办法了,就像最初谷歌将Kotlin定为Android干流语言时咱们学习Kotlin相同,未来Jetpack Compose 必定会是Android UI开发的干流办法。
- Flutter 的定位是多渠道 UI 结构,优势在于跨渠道。
大家很喜欢把Jetpack Compose 和 Flutter作比照,不知道该学哪一个?的确,某些场景下它们的确挺像的,而且还都是谷歌在推的。
个人了解是:假如你未来的主攻方向还是Android,那么无脑挑选Jetpack Compose,虽然Compose现在也能完成跨端,但跨端现在看并不是它的首要作业;而假如你的方向是多渠道开发,那么学习Flutter是首选吧。
别的,与其一直纠结学哪一个,不如直接上手亲身感触下它们的不同,正所谓 “纸上得来终觉浅,绝知此事要躬行”。
Jetpack Compose入门
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Text("Hello World!")
}
}
}
其间,setContent()传入一个@Composable作用域,其作用跟之前的setContentView()相同用来设置界面。Text()用来描绘一个UI元素,里面有各种参数,这儿咱们只把案牍填上去,履行成果:
一个最简单的功能就完成了。
1、@Composable 可组合函数
还是上述展现一个文本的功能,咱们换一种写法:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MessageCard("Android")
}
}
}
@Composable
fun MessageCard(name: String) {
Text(text = "Hello $name!")
}
履行作用跟上面相同。唯一的区别便是把文本展现单独抽离到一个办法中了,并且该办法上面加了@Composable 注解:
@Composable注解用于标记一个函数为可组合函数。可组合函数是一种特别的函数,不需要回来任何UI元素,因为可组合函数描绘的是所需的屏幕状况,而不是结构界面widget;而假如按咱们曾经的XML编程办法,必须在办法中回来UI元素才干运用它(如回来View类型)。
@Composable注解的函数之间能够彼此调用,因为这样Compose结构才干正确处理依赖联系。别的,@Composable函数中也能够调用一般函数,而一般函数中却不能直接调用@Composable函数。 这儿能够类比下kotlin中suspend挂起函数的用法,其用法是类似的。
几个定义:
- 组合:对 Jetpack Compose 在履行可组合项时所构建界面的描绘。
- 初始组合:经过首次运转可组合项创立组合。
-
重组:
在数据发生变化时从头运转可组合项以更新组合
。
可组合函数的特色:
- 运用同一参数多次调用此函数时,它的行为办法相同,并且它不运用其他值,如全局变量或对 random() 的调用。
- 此函数描绘界面而没有任何副作用,如修改属性或全局变量、点击事情的处理等。当需要履行顺便效应时,应经过回调触发。如:
@Composable
private fun NamePickerItem(name: String, onClicked: (String) -> Unit) {
Text(name, Modifier.clickable(onClick = { onClicked(name) }))
}
可见经过回调,点击事情这个顺便效应是在调用方触发的。
在编译时,Jetpack Compose会将标记为@Composable的函数编译成字节码,并生成一个专门的ComposeNode类来办理其状况和属性。这个类会自动处理依赖联系,并在需要时核算UI元素。这样,开发者就能够专注于编写UI逻辑,而不必忧虑状况办理和UI更新的细节。
这儿引出一个问题,Compose 是如何做 UI 更新的呢?总不能每次有一小部分数据的变化,整个UI都要跟着改写一次吧,那功能必定差的要死。其实,当有数据变化时,Compose完成的是增量更新,只会从头制作数据有改动的UI(该进程称为重组),数据没有改动的则不会从头制作了。
2、布局根底知识
Compose 经过元素组合、布局、制作之后能够将状况转换为UI元素。
组合
在 Compose 中,能够经过从可组合函数中调用其他可组合函数来构建界面层次结构。 如图所示:
- Column :能够将多个项垂直地放置在屏幕上;
- Row :能够将多个项水平地放置在屏幕上;
- Box :可将元素放在其他元素上,还支撑为其包含的元素配置特定的对齐办法。
摆放及对齐办法:
/**
* @param verticalArrangement 竖直摆放办法
* @param horizontalAlignment 水平对齐办法
*/
inline fun Column(
modifier: Modifier = Modifier,
verticalArrangement: Arrangement.Vertical = Arrangement.Top,
horizontalAlignment: Alignment.Horizontal = Alignment.Start,
content: @Composable ColumnScope.() -> Unit
) {...}
/**
* @param horizontalArrangement 水平摆放办法
* @param verticalAlignment 竖直对齐办法
*/
@Composable
inline fun Row(
modifier: Modifier = Modifier,
horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
verticalAlignment: Alignment.Vertical = Alignment.Top,
content: @Composable RowScope.() -> Unit
) {...}
/**
* @param contentAlignment 内容对齐办法
*/
@Composable
inline fun Box(
modifier: Modifier = Modifier,
contentAlignment: Alignment = Alignment.TopStart,
propagateMinConstraints: Boolean = false,
content: @Composable BoxScope.() -> Unit
) {...}
verticalArrangement、horizontalArrangement 摆放办法及作用:
布局
界面树布局经过单次传递即可完成。父节点会在其子节点之前进行丈量,但会在其子节点的尺度和放置位置确认之后再对自身进行调整。 当界面树较深时,Compose 能够经过只丈量一次子项来完成高功能。
3、Modifier润饰符
能够经过Modifier润饰符更改可组合项的巨细、布局、外观,还能够增加高档互动,例如使元素可点击等。如:
Image(
painter = painterResource(id = R.mipmap.icon_water_melon),
contentDescription = "",
modifier = Modifier
.size(50.dp)
.clip(CircleShape)
.border(width = 2.dp, Color.Red, CircleShape)
)
履行成果: ,原图自身是长方形的,经过Modifier润饰符润饰后,很容易变成圆角图片。想一下假如用XML办法来写,是不是要写很多代码呢。
4、存储状况
可组合函数中能够运用 remember 将本地状况存储在内存中,并盯梢传递给 mutableStateOf 的值的变化。该值更新时,体系会自动从头制作运用此状况的可组合项(及其子项),这也是上面所说的重组。如:
@Composable
fun MessageCard(msg: Message) {
// We keep track if the message is expanded or not in this variable
var isExpanded by remember { mutableStateOf(false) }
// We toggle the isExpanded variable when we click on this Column
Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {...}
}
当点击Column
元素时,每次都会从头履行MessageCard()可组合函数进行改写,而经过remember和mutableStateOf能够保存了上次的isExpanded状况;假如不运用它们,从头履行 MessageCard() 时 isExpanded 也会从头初始化。
除了remember之外,还有rememberSaveable、savedStateHandle.saveable等。。。
总结
这篇文章首要讲了Compose是什么以及咱们要开始学习它的必要性。作为Compose 第一篇介绍文章,本文旨在开始感触一下 Compose的能力,后续再具体研讨 Compose 的精彩用法!
资料
【1】谷歌Jetpack Compose 教程:
https://developer.android.com/jetpack/compose/tutorial?hl=zh-cn