Jetpack Compose 是个啥?为啥要学它?

谷歌对 Jetpack Compose 的定义:

Jetpack Compose 是推荐用于构建原生 Android 界面的新工具包。它可简化并加速 Android 上的界面开发,运用更少的代码、强壮的工具和直观的 Kotlin API,快速打造生动而精彩的运用。

提取关键词:界面开发新工具包、简化并加速界面开发、Kotlin API

对于大部分Android项目来说,假如根底库(如网络库、hybird、图片加载、热修复库等)现已搭好,那么平常大部分时刻便是跟 UI界面、需求逻辑 打交道了,而谷歌供给的 Jetpack Compose 正好是加速界面开发的工具包

对于Android开发,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 逐渐安稳了,功能也越来越好了。

对于Android开发,Jetpack Compose真的要开始学起来了?

  • 更少的代码:编写代码只需要采用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元素,里面有各种参数,这儿咱们只把案牍填上去,履行成果:

对于Android开发,Jetpack Compose真的要开始学起来了?

一个最简单的功能就完成了。

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、布局根底知识

对于Android开发,Jetpack Compose真的要开始学起来了?
Compose 经过元素组合、布局、制作之后能够将状况转换为UI元素。

组合

在 Compose 中,能够经过从可组合函数中调用其他可组合函数来构建界面层次结构。

对于Android开发,Jetpack 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 摆放办法及作用:

对于Android开发,Jetpack Compose真的要开始学起来了?

布局

界面树布局经过单次传递即可完成。父节点会在其子节点之前进行丈量,但会在其子节点的尺度和放置位置确认之后再对自身进行调整

对于Android开发,Jetpack Compose真的要开始学起来了?
当界面树较深时,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)
   )

履行成果:

对于Android开发,Jetpack Compose真的要开始学起来了?
,原图自身是长方形的,经过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