什么是 Jetpack Compose
Jetpack Compose是Google I/O 2019 发布的Andorid UI框架,它不同于Andorid常见的Xml+命令式Coding的UI开发范式,而是基于Kotlin的DSL实现了一套类似React的声明式UI框架。Jetpack Compose目前仍然处于pre-alpha版本,目标是2020年能够发布稳定的Beta版本。伴随React Native、Flutter等大前端框架的兴起以及Jetpack Compose、SwiftUI等native框架的出现,声明式UI正逐渐成为客户端UI开发的新趋势。我们通过一个小sample来学习和体验一下Jetpack Compose带来的新的开发方式
开发环境
由于Jetpack Compose还未正式发布,需要使用Preview版的AndroidStudio进行体验:
- Android Studio4.0 Canary3
- targetSdkVersion 29
新建Project,选择 Empty Compose Activity
@Compose组件
Compose的API非常友好,通过为函数添加@Composable注解,将其声明为一个可以在DSL中使用的UI组件。之后在Activity中可以通过setContent{...}方法使用DSL声明UI布局:
//MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Greeting(name = "Android")
}
}
}
@Composable
fun Greeting(name: String) {
Text (text = "Hello $name!")
}
使用IDE进行Priview
从Android Studio4.0 Canary1起,可以在IDE中对@Comopse组件进行预览。在@Compose函数上添加@Preview即可进行预览。需要注意的是用Compose的代码发生变更后经过build才能在预览中反映出来,不像xml的预览那么实时,这是因为compose的代码需要经过编译生成新的class后才能再次运行从而生效,而xml的变动是无需经过编译的。
另外需注意的是@Preview的组件不能有参数,所以Greeting组件需要向下面这样进行预览
@Composable
fun Greeting(name: String) {
Text (text = "Hello $name!")
}
@Preview
@Composable
fun PreviewGreeting() {
Greeting("Android")
}
在IDE中就可以预览的效果如下:
Sample实现
了解了基本使用之后,我们实现一个简单的Sample,用来显示文章列表:
dataclass
首先,定义sample中需要使用的data class
//Article.kt
data class Article(
val id: String,
val title: String,
val url: String,
val user: User
)
//User.kt
data class User(
val id: String,
val name: String,
val profileImageUrl: String
)
ArticleItem
接下来实现文章列表Item的UI,由于用到了DrawImage组件,先在build.gradle中添加以下依赖
dependencies{
implementation 'androidx.ui:ui-foundation:0.1.0-dev03'
}
相比传统的通过Class定义自定义控件的方式,定义Compose组件只需要定义一个function:
@Composable
fun ArticleItem(article: Article) {
val image = +imageResource(R.drawable.ic_header)
val typography = +MaterialTheme.typography()
Row(modifier = Spacing(16.dp)) {
Container(modifier = Size(60.dp, 60.dp)) {
DrawImage(image = image)
}
Column(modifier = ExpandedWidth wraps Spacing(right = 16.dp, left = 16.dp)) {
Text(article.title, style = typography.h6)
Text(article.user.name, modifier = Spacing(top = 4.dp), style = typography.subtitle2)
}
}
}
function内部可以调用其他的@Compose的function,从而实现有层级的UI。上面代码中使用到下列Compose组件:
- Row
- 水平并排显示多个组件,类似于orientation为horizontal的LinearLayout
- Container
- 可以按照指定大小显示内部元素,常用来显示DrawImage等
- DrawImage
- 用来显示Image
- Column
- 垂直并排显示显示多个组件,类似于orientation为vertical的LinearLayout
- Text
- 显示文本,可以通过style指定TextSize
- Spacing
- 用来设置margin
可见,用Andorid传统的布局方式不同,ComposeI采用类似H5或Flutter中广泛使用的Flexbox布局方式。
ArticleList
由Item构成文章列表
//ArticleList.kt
@Composable
fun ArticleList(articles: List<Article>) {
VerticalScroller {
Column {
articles.forEach { article ->
Card(
modifier = Spacing(4.dp) wraps Expanded,
shape = RoundedCornerShape(8.dp)
) {
ArticleItem(article = article)
}
}
}
}
}
- VerticleScroller
- 垂直方向的滚动
- Card
- 相当于Android的CardView
MaiActivity
在MainAcitity中显示文章列表:
//MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val articles = mutableListOf<Article>()
repeat(11) {
articles.add(
Article(
id = "$it",
title = "Kotlin入门",
url = "http://www.exsample.com/articles/$it",
user = User(id = "123", name = "第${it}讲...", profileImageUrl = "")
)
)
}
setContent {
MaterialTheme {
ArticleList(articles = articles)
}
}
}
}
文章列表显示如下:
增加Toolbar
最后我们可以在顶部增加Toolbar,让显示效果更完善。可以通过Column将Toolbar放置在顶部:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
Column {
TopAppBar(title = {
Text("Kotlin入门")
})
ArticleList(articles = articles)
}
}
}
}
}
总结
通过上面的sample我们了解了如何使用Jetpack Compose进行一个简单的UI布局。但Compose绝不仅仅是用来布局的工具,否则和Anko有什么区别呢?它真正强大的是包晗状态管理在内的一整套声明式UI的编程范式,关于这些的学习我们后面再另开文章介绍。Jetpack Compose吸收了很多前端框架的设计思想,例如用function替代class明显是来自React的函数式组件的灵感,这些变化会让习惯与写OOP程序的同学们有一种耳目一新的感觉,但是不可否认的是现阶段无论功能和性能上,Jetpack Compose距离”可用”还有很大一段距离,相信不久的未来Beta版的推出会给我们带来更多惊喜。