Jetpack Compose intro

Jetpack Compose 是 Google 开发的现代 Declarative UI framework,如果有开发过 Swift UI 、React 或是 Flutter 就会发现他们都极为类似。Google 提供了非常丰富的文件与教学,有兴趣深入研究的话,非常推荐去看,内容会比我这里详细很多。

在这篇文章中,我比较注重的是他与原生 Android View 的不同之处,以及 Jetpack Compose 到底好在哪里,首先我们来看看 build.gradle 要加入怎麽样的 dependency 吧!

implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation 'androidx.activity:activity-compose:$compose_activity_version'
  • ui - 基本元件以及绘制。
  • material - 提供常用的 Material Design 元件以及 Theme。
  • ui-tooling-preview - 提供元件的预览,让我们可以直接在 Android Studio 看到我们设计出来的样子。
  • activity-compose - 跟 Activity 的整合,例如 BackHandler, ActivityResult 以及 setContent。

如何使用

在 Activity 中的使用方法非常简单,只要使用 setContent 这个函式就可以了,由於这个函式的最後一个参数是个函式(也就是说setContent 是一个 higher order function),所以结尾可以使用 lambda 来表示要被执行的内容。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            MyTheme {
                HomeScreen()
            }
        }
    }
}

Composable function

每一个 Jetpack Compose 的函式都有一个特殊的 Annotation - Composable ,有了这个 Annotation ,编译器就知道如何去自动生成所需要的程序码,这些自动生成的程序码会去连结 UI 元件的生命周期事件、状态管理、Material Theming 等等,如此一来,在我们的日常开发中就不会被这些技术细节给干扰,在接下来的文章中你将会很常看到它。

在原生系统中,与 Composable function 相对应的应该就是 Custom View 了,如果是一个有组合效果的元件,像是一个 Image 配上 Text 好了,在 Custom View 中你可能会 Inflate 一个 xml layout,然後用 findViewById 将他们拿出来使用,或是藉由建构子去创建这些元件,然後使用 addView 这个 function 将他们加进来,这些 View 的大小还要自己用麻烦的 LayoutParam 来去定义,不管哪条路都没有多容易。如果是使用 Jetpack Compose 就简单很多了,完全不用去管这些技术实作细节,只要专注在“描述”就行了,像下面这样子:

@Composable
fun Greeting(name: String) {
    Row {
        Image(
            painter = painterResource(id = R.drawable.ic_baseline_add_24),
            contentDescription = "Add"
        )
        Text(text = "Hello $name!")
    }
}

这里补充一下:不一定所有的 Composable function 都会是用来显示的 View ,像是动画相关的 API,他们也是 Composable function,但不是一个独立的View。

Preview

@Preview (showBackground = true)
@Composable
fun HomeScreenPreview() {
    MyTheme {
        HomeScreen()
    }
}

在 Jetpack Compose 之中,除了 Composable 之外,还有另一个常用的 Annotation - Preview,他的作用是可以让你在 Android Studio 中看到预览画面,而不需要执行在手机上。跟之前的 Android View 系统比较起来,虽然 xml 也可以预览,但是 xml 的缺点就是太静态了,无法轻易地看到所有状态(例如选择状态)、只能看到一个萤幕画面,所以在很多时候如果要看到实际效果的话,就只能跑在手机上面。但是 Jetpack Compose 的 Preview 可以让你同时显示多个小预览,也可以像 xml 一样显示单个页面,弹性非常大,但是缺点是效能还有待加强,在目前的 1.0 版本中,从修改程序码,到 build ,到产生预览所花的时间会超过 5 秒以上,也有可能要到 30 秒,最理想的情况应该是要不超过一秒。

排版

在 Jetpack Compose 中的排版中,最基本的就是 Box、Row 与 Column 了,Box 跟 FrameLayout 非常类似,可以指定 Children 在排版中的对齐位置,不一样的是,FrameLayout 使用 Gravity 来表示对齐概念,Box 则是用 Alignment 来表示,下方是各方向对齐的示意图以及程序码:

Screen Shot 2021-08-24 at 2.05.53 PM.png

@Composable
fun BoxSample() {
    Box(Modifier.fillMaxSize()) {
        Text("TS", modifier = Modifier.align(Alignment.TopStart))
        Text("TC", modifier = Modifier.align(Alignment.TopCenter))
        Text("TE", modifier = Modifier.align(Alignment.TopEnd))
        Text("CS", modifier = Modifier.align(Alignment.CenterStart))
        Text("C", modifier = Modifier.align(Alignment.Center))
        Text("CE", modifier = Modifier.align(Alignment.CenterEnd))
        Text("BS", modifier = Modifier.align(Alignment.BottomStart))
        Text("BC", modifier = Modifier.align(Alignment.BottomCenter))
        Text("BE", modifier = Modifier.align(Alignment.BottomEnd))
    }
}

@Preview(showBackground = true)
@Composable
fun BoxSamplePreview() {
    Surface(modifier = Modifier.size(100.dp, 100.dp)) {
        BoxSample()
    }
}

Modifier

Modifier 是 Jetpack Compose 中非常重要的一个元素,用来对当下的 View 增加行为,或是做排版相关的事项。定位有点像是 xml 中的 attribute,像是 layout_gravity、width、height、wrap_content、padding、margin 等等。与 xml attribute 不同的是,Modifier 在 Jetpack Compose 中有了更明确的分类方式,一些不是广泛用途的 attribute。像是 text、textColor、font 等等就不会是透过 Modifier 来设定,而是透过 function 的参数来设定。

// 在这例子中,参数就是 name
@Composable
fun Greeting(name: String) {
    Row {
        Image(
            painter = painterResource(id = R.drawable.ic_baseline_add_24),
            contentDescription = "Add"
        )
        Text(text = "Hello $name!")
    }
}

然而在 Custom View 要新增自己的参数(Attribute)是一件很麻烦的事,像是要建立一个新的 Styleable,然後要在 Custom View 的 Constructor 中实作你要如何读这些参数(如下方程序码所示),还要详细的阅读文件才能确保你的实作步骤是没有错的。然而这些对於 Android View 来说是有必要的,因为这些新的参数跟 width 、height 这种广泛用途的参数是同一个进入点: xml 。所以如果要藉由 xml 来做这些比较方便的设定,就得要照 Android framework 所定的规矩来实作才行。相对的, Jetpack Compose 是纯 Kotlin 语言所建构出来的,所以“新增参数”这件事变得简单无比,把它当正常函数来写就好。

init {
    // Custom View 加入自定义参数的方式,繁琐的技术细节以及实作
    context.theme.obtainStyledAttributes(
            attrs,
            R.styleable.PieChart,
            0, 0).apply {

        try {
            mShowText = getBoolean(R.styleable.PieChart_showText, false)
            textPos = getInteger(R.styleable.PieChart_labelPosition, 0)
        } finally {
            recycle()
        }
    }
}

Column & Row

Column 跟 Row 对应的就是 LinearLayout,使用起来非常简单,请看以下范例:

Screen Shot 2021-08-24 at 2.43.54 PM.png

@Composable
fun RowSample() {
    Row {
       Text(text = "Hello", color = Color.Cyan)
       Text(text = "Compose", color = Color.Red)
       Text(text = "And", color = Color.Blue)
       Text(text = "Kotlin", color = Color.Green)
    }
}

@Preview(showBackground = true)
@Composable
fun SamplePreview() {
    Surface {
        RowSample()
    }
}

Row 就是水平的 LinearLayout , Column 则是垂直的 LinearLayout ,这边就不多示范了。

下一篇将会开始使用 Jetpack Compose 来画出便利贴。


<<:  Spring Framework X Kotlin Day 3 IOC/DI

>>:  从精准回馈来看成长重要性

.Net Core Web Api_笔记03_HTTP资源操作模式POST

上一篇介绍到GET主要用於资料获取 HttpPost主要用於资料添加 这里我们沿用之前专案新增一个T...

SQL Server Collation (定序) 设定 - 心得分享

DBA Bootcamp 有听过 SQL Server 的 collation (定序)设定吗?讲到...

(Day15) 闭包进阶使用,工厂模式及私有方法。

上回介绍闭包概念以及闭包大致运用,这次则介绍实做比较常用闭包的几种模式 工厂模式 上个章节有介绍到,...

[Tableau Public] day 23:台湾姓氏分布分析-1

昨天我们已经调整了栏位(把日期栏位移除&把英文栏位移除更新成中文栏位)跟新增了经纬度栏位(先去找到各...

[第六天]从0开始的UnityAR手机游戏开发-如何汇入Unity Package到Unity和Unity使用Vuforia插件的基本设置

Unity Package汇入方式 Unity Package汇入Unity有以下3种方式 双击两...