Android Jetpack Compose 最全上手指南 | 开发者说·DTalk

Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第1张图片

本文原作者: 码农西哥,原文发布于微信公众号: Android 技术杂货铺 

https://mp.weixin.qq.com/s/7tKv_RamfW0rG8tZHXH_rg

在 2019 年的 Google/IO 大会上,亮相了一个全新的 Android 原生 UI 开发框架 - Jetpack Compose,与苹果的 SwiftIUI 一样,Jetpack Compose 是一个声明式的 UI 框架,随着安卓和苹果两大移动平台相继推出自己的 UI 开发框架 Jetpack Compose 和 SwiftIUI,标志着移动操作系统正式全面拥抱声明式 UI 开发模式。

声明式 UI 的前世今生

其实声明式 UI 并不是什么新技术,早在 2006 年,微软就已经发布了其新一代界面开发框架 WPF,其采用了 XAML 标记语言,支持双向数据绑定、可复用模板等特性。

2010 年,由诺基亚领导的 Qt 团队也正式发布了其下一代界面解决方案 Qt Quick,同样也是声明式,甚至 Qt Quick 起初的名字就是 Qt Declarative。QML 语言同样支持数据绑定、模块化等特性,此外还支持内置 JavaScript,开发者只用 QML 就可以开发出简单的带交互的原型应用。

声明式 UI 框架近年来飞速发展,并且被 Web 开发带向高潮。React 更是为声明式 UI 奠定了坚实基础并一直引领其未来的发展。随后 Flutter 的发布也将声明式 UI 的思想成功带到移动端开发领域...

声明式 UI 的意思就是,描述你想要一个什么样的 UI 界面,状态变化时,界面按照先前描述的重新 "渲染" 即可得到状态绝对正确的界面,而不用像命令一样,告诉程序一步一步该干什么,维护各种状态。

Jetpack Compose 介绍

Jetpack Compose 是一个用于构建原生 Android UI 的现代化工具包,它基于声明式的编程模型,因此你可以简单地描述 UI 的外观,而 Compose 则负责其余的工作-当状态发生改变时,你的 UI 将自动更新。由于 Compose 基于 Kotlin 构建,因此可以与 Java 编程语言完全互操作,并且可以直接访问所有 Android 和 Jetpack API。它与现有的 UI 工具包也是完全兼容的,因此你可以混合原来的 View 和现在新的 View,并且从一开始就使用 Material 和动画进行设计。

Jetpack Compose 环境准备和 Hello World

每当我们学习一门新的语言,我们都是从一个 hello world 开始,今天我们也从一个 hello world 来开始 Jetpack Compose 吧! 要想获得 Jetpack Compose 的最佳体验,我们需要下载最新版本的 Android Studio 预览版本 (即 Android Studio 4.0)。因为 Android Studio 4.0 添加了对 Jetpack Compose 的支持,如新的 Compose 模版和 Compose 及时预览。

Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第2张图片

Android Studio 4.0.png

使用 Jetpack Compose 来开始你的开发工作有两种方式:

  • 将 Jetpack Compose 添加到现有项目

  • 创建一个支持 Jetpack Compose 的新应用

将 Jetpack Compose 添加到现有项目

如果你想在现有的项目中使用 Jetpack Compose,你需要配置一些必须的设置和依赖:

gradle 配置

在 app 目录下的 build.gradle 中将 app 支持的最低 API 版本设置为 21 或更高,同时开启 Jetpack Compose enable 开关,代码如下:

android {
    defaultConfig {
        ...
        minSdkVersion 21
    }


    buildFeatures {
        // Enables Jetpack Compose for this module
        compose true
    }
    ...


    // Set both the Java and Kotlin compilers to target Java 8.


    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }


    kotlinOptions {
        jvmTarget = "1.8"
    }
}

使用试验版 Kotlin-Gradle 插件

Jetpack Compose 需要试验版的 Kotlin-Gradle 插件,在根目录下的 build.gradle 添加如下代码:

buildscript {
    repositories {
        google()
        jcenter()
        // To download the required version of the Kotlin-Gradle plugin,
        // add the following repository.
        maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
    ...
    dependencies {
        classpath 'com.android.tools.build:gradle:4.0.0-alpha01'
        classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.60-eap-25'
    }
}


allprojects {
    repositories {
        google()
        jcenter()
        maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
    }
}

添加 Jetpack Compose 工具包依赖项

在 app 目录下的 build.gradle 添加 Jetpack Compose 工具包依赖项,代码如下:

dependencies {
    // You also need to include the following Compose toolkit dependencies.
    implementation 'androidx.ui:ui-tooling:0.1.0-dev02'
    implementation 'androidx.ui:ui-layout:0.1.0-dev02'
    implementation 'androidx.ui:ui-material:0.1.0-dev02'
    ...
}

ok,到这儿准备工作就完毕,就可以开始写代码了,但是前面说了,还有一种方式接入 Jetpack Compose,我们来一起看看。

创建一个支持 Jetpack Compose 的新应用

比起在现有应用中接入 Jetpack Compose,创建一个支持 Jetpack Compose 的新项目则简单了许多,因为 Android Studio 4.0 提供了一个新的 Compose 模版,只要选择这个模版创建应用,则所有上面的那些配置项都自动帮我们完成了。

创建一个支持 Jetpack Compose 的应用,如下几个步骤就可以了:

  1. 如果你在 Android Studio 的欢迎窗口,点击 Start a new Android Studio project,如果你已经打开了 Android Studio 项目,则在顶部菜单栏选择 File > New > New Project

  2. Select a Project Template 窗口,选择 Empty Compose Activity 并且点击下一步

  3. Configure your project 窗口,做如下几步:

    1. 设置项目名称包名保存位置

    2. 注意,在语言下来菜单中,Kotlin 是唯一一个可选项,因为 Jetpack Compose 只能用 Kotlin 来写的才能运行。

    3. Minimum API level 下拉菜单中,选择 21 或者更高

  4. 点击 Finish

现在,你就可以使用 Jetpack Compose 来编写你的应用了。

Hello wold

MainActivity.kt 中添加如下代码:

class MainActivity : AppCompatActivity() {
    overridefun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
             Text("Hello, Android技术杂货铺")
        }
    }
}

Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第3张图片

hello.png

Jetpack Compose 是围绕 composable 函数来构建的。这些函数使你可以通过描述应用程序的形状和数据依赖,以编程方式定义应用程序的 UI,而不是着眼于 UI 的构建过程。要创建 composable 函数,只需要在函数名前面加上一个 @composable 注解即可,上面的 Text 就是一个 composable 函数。

定义一个 composable 函数

一个 composable 函数只能在另一个 composable 函数的作用域里被调用,要使一个函数变为 composable 函数,只需在函数名前加上 @composable 注解,我们把上面的代码中,setContent 中的部分移到外面,抽取到一个 composable 函数中,然后传递一个参数 nametext 元素。

class MainActivity : AppCompatActivity() {
    overridefun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Greeting("Android技术杂货铺")
        }
    }
}


@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!")
}

Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第4张图片

布局

UI 元素是分层级的,元素包含在其他元素中。在 Jetpack Compose 中,你可以通过从其他 composable 函数中调 composable 函数来构建 UI 层次结构。

Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第5张图片

在 Android 的 xml 布局中,如果要显示一个垂直结构的布局,最常用的就是 LinearLayout,设置 android:orientation 值为 vertical,子元素就会垂直排列,那么,在 Jetpack Compose 中,如何来实现垂直布局呢?先添加几个 Text 来看一下。

添加多个 Text

在上面的例子中,我们添加了一个 Text 显示文本,现在我们添加三个文本,代码如下:

class MainActivity : AppCompatActivity() {
    overridefun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NewsStory()
        }
    }
}


@Composable
fun NewsStory() {
    Text("我超❤️JetPack Compose的!")
    Text("Android技术杂货铺")
    Text("依然范特西")
}

Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第6张图片

从上图可以看到,我们添加了三个文本,但是,由于我们还没有提供有关如何排列它们的任何信息,因此三个文本元素相互重叠绘制,使得文本不可读。

使用 Column

要使重叠绘制的 Text 文本能够垂直排列,我们就需要使用到 Column 函数,写过 flutter 的同学看起来是不是很眼熟?是的,跟 flutter 里面的 Column Widget 名字和功能完全一样,甚至连他们的属性都一模一样。

@Composable
fun NewsStory() {
    Column { //  添加Column,使布局垂直排列
        Text("我超❤️JetPack Compose的!")
        Text("Android技术杂货铺")
        Text("依然范特西")
    }
}

Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第7张图片

可以看到,前面重叠的布局,现在已经垂直排列了,但是,默认情况下,从左上角开始,一个接一个的排列,没有任何间距。接下来,我们给 Column 设置一些样式。

给 Column 添加样式

在调用 Column () 时,可以传递参数给 Column () 来配置 Column 的大小、位置以及设置子元素的排列方式。

@Composable
fun NewsStory() {
    Column (
        crossAxisSize = LayoutSize.Expand,
        modifier = Spacing(16.dp)
    ){ //  添加Column,使布局垂直排列
        Text("我超❤️JetPack Compose的!")
        Text("Android技术杂货铺")
        Text("依然范特西")
    }
}

Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第8张图片

如上图所示,我们填充了 padding,其他效果几乎一模一样,上面代码中的设置属性解释如下:

  • crossAxisSize: 指定 Column 组件 (注: Compose 中,所有的组件都是 composable 函数,文中的组件都是指代 composable 函数) 在水平方向的大小,设置 crossAxisSizeLayoutSize.Expand 即表示 Column 宽度应为其父组件允许的最大宽度,相当于传统布局中的 match_parant,还有一个值为 LayoutSize.Wrap,看名字就知道,包裹内容,相当于传统布局中的 wrap_content

  • modifier: 使你可以进行其他格式更改。在这种情况下,我们将应用一个 Spacing 修改器,该设置将 Cloumn 与周围的视图产生间距。

如何显示一张图片?

在原来的安卓原生布局中,显示图片有相应的控件 ImageView,设置本地图片地址或者 Bitmap 就能展示,在 Jetpack Compose 中该如何显示图片呢?

Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第9张图片

我们先下载这张图片到本地,添加到资源管理器中,命名为 header.png,我们更改一下上面的 NewsStory () 方法,先从资源文件夹获取图片 image,然后通过 DrawImage() 将图片绘制出来: 

@Composable
fun NewsStory() {
    // 获取图片
    val image = +imageResource(R.mipmap.header)
    Column (
        crossAxisSize = LayoutSize.Expand,
        modifier = Spacing(16.dp)
    ){ //  添加Column,使布局垂直排列
        // 显示图片
        DrawImage(image)


        Text("我超❤️JetPack Compose的!")
        Text("Android技术杂货铺")
        Text("依然范特西")
    }
}

Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第10张图片

可以看到,图片不会按正确的比列显示,接下来,我们来修复它。

图片已添加到布局中,但会展开以填充整个视图,并和文本是拼叠排列,文字显示在上层。要设置图形样式,请将其放入 Container (又一个和 flutter 中一样的控件)

  • Container: 一个通用的内容对象,用于保存和安排其他 UI 元素。然后,你可以将大小和位置的设置应用于容器。

@Composable
fun NewsStory() {
    // 获取图片
    val image = +imageResource(R.mipmap.header)
    Column (
        crossAxisSize = LayoutSize.Expand,
        modifier = Spacing(16.dp)
    ){ //  添加Column,使布局垂直排列
        // 放在容器中,设置大小
        Container(expanded = true, height = 180.dp) {
            // 显示图片
            DrawImage(image)
        }
        Text("我超❤️JetPack Compose的!")
        Text("Android技术杂货铺")
        Text("依然范特西")
    }
}

Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第11张图片

  • expanded: 指定 Container 的大小,默认是 false (Container 的大小是子组件的大小,相当于 wrap_content),如果将它设置为 true,就指定 Container 的大小为父控件所允许的最大 size, 相当于 match_parent

  • height: 设置 Container 容器的高度,height 属性的优先级高于 expanded,因此会覆盖 expanded,如上面的例子,设置 height180dp,也就是容器宽为父控件宽度,高为 180dp

添加间距 Spacer

我们看到,图片和文本之间没有间距,传统布局中,我们可以添加 Margin 属性,设置间距,在 Jetpack Compose 中,我们可以使用 HeightSpacer()WidthSpacer() 来设置垂直和水平间距。

 HeightSpacer(height = 20.dp) //设置垂直间距20dp
 WidthSpacer(width = 20.dp) // 设置水平间距20dp

在上面的例子中,我们来为图片和文本之间添加 20dp 的间距:

@Composable
fun NewsStory() {
    // 获取图片
    val image = +imageResource(R.mipmap.header)
    Column (
        crossAxisSize = LayoutSize.Expand,
        modifier = Spacing(16.dp)
    ){ //  添加Column,使布局垂直排列
        // 放在容器中,设置大小
        Container(expanded = true, height = 180.dp) {
            // 显示图片
            DrawImage(image)
        }


        HeightSpacer(height = 20.dp) // 添加垂直方向间距20dp


        Text("我超❤️JetPack Compose的!")
        Text("Android技术杂货铺")
        Text("依然范特西")
    }
}

Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第12张图片

使用 Material design 设计

Compose 旨在支持 Material Design 设计原则,许多组件都实现了 Material Design 设计,可以开箱即用,在这一节中,将使用一些 Material 小组件来对 app 进行样式设置

Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第13张图片

添加 Shape 样式

Shape 是 Material Design 系统中的支柱之一,我们来用 clip 函数对图片进行圆角裁剪。

@Composable
fun NewsStory() {
    // 获取图片
    val image = +imageResource(R.mipmap.header)
    Column (
        crossAxisSize = LayoutSize.Expand,
        modifier = Spacing(16.dp)
    ){ //  添加Column,使布局垂直排列
        // 放在容器中,设置大小
        Container(expanded = true, height = 180.dp) {
            Clip(shape = RoundedCornerShape(10.dp)) {
                // 显示图片
                DrawImage(image)
            }


        }


        HeightSpacer(height = 20.dp) // 添加垂直方向间距20dp


        Text("我超❤️JetPack Compose的!")
        Text("Android技术杂货铺")
        Text("依然范特西")
    }
}


Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第14张图片

形状是不可见的,但是我们的图片已经被裁剪了成了设置的形状样式,因此如上图,图片已经有圆角了。

给 Text 添加一些样式

通过 Compose,可以轻松利用 Material Design 原则。将 MaterialTheme () 应用于创建的组件

@Composable
fun NewsStory() {
    // 获取图片
    val image = +imageResource(R.mipmap.header)
    // 使用Material Design 设计
    MaterialTheme() {
        Column (
            crossAxisSize = LayoutSize.Expand,
            modifier = Spacing(16.dp)
        ){ //  添加Column,使布局垂直排列
            // 放在容器中,设置大小
            Container(expanded = true, height = 180.dp) {
                Clip(shape = RoundedCornerShape(10.dp)) {
                    // 显示图片
                    DrawImage(image)
                }


            }


            HeightSpacer(height = 20.dp) // 添加垂直方向间距20dp


            Text("我超❤️JetPack Compose的!")
            Text("Android技术杂货铺")
            Text("依然范特西")
        }
    }
}


如上面的代码,添加了 MaterialTheme 后,重新运行,效果没有任何变化,文本现在使用了 MaterialTheme 的默认文本样式。接下来,我们将特定的段落样式应用于每个文本元素。

@Composable
fun NewsStory() {
    // 获取图片
    val image = +imageResource(R.mipmap.header)
    // 使用Material Design 设计
    MaterialTheme() {
        Column (
            crossAxisSize = LayoutSize.Expand,
            modifier = Spacing(16.dp)
        ){ //  添加Column,使布局垂直排列
            // 放在容器中,设置大小
            Container(expanded = true, height = 180.dp) {
                Clip(shape = RoundedCornerShape(10.dp)) {
                    // 显示图片
                    DrawImage(image)
                }


            }
            HeightSpacer(height = 20.dp) // 添加垂直方向间距20dp


            Text("我超❤️JetPack Compose的!", style = +themeTextStyle { h5 }) // 注意添加了style
            Text("Android技术杂货铺", style = +themeTextStyle { body1 }) // 注意添加了style
            Text("依然范特西", style = +themeTextStyle { body2 }) // 注意添加了style
        }
    }
}

Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第15张图片

现在看看,我们的文本样式已经有变化了,标题有 6 中样式 h1-h6,其实 HTML 中的样式很像,内容文本有 body1body2 两种样式。

Material 调色版使用了一些基本颜色,如果要强调文本,可以调整文本的不透明度:

  Text("我超❤️JetPack Compose的!", style = (+themeTextStyle { h5 }).withOpacity(0.87f))
  Text("Android技术杂货铺", style = (+themeTextStyle { body1 }).withOpacity(0.87f))
  Text("依然范特西", style = (+themeTextStyle { body2 }).withOpacity(0.6f))

Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第16张图片

有些时候,标题很长,但是我们又不想长标题换行从而影响我们的 app UI,因此,我们可以设置文本的最大显示行数,超过部分就截断。

Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第17张图片

如本例所示,我们设置显示最大行数为 2,多于的部分截断处理:

  Text("我超❤️JetPack Compose的!写起来简单,复用性又强,可以抽取很多组件来复用,不用管理复杂的状态变更!",
                maxLines = 2, overflow = TextOverflow.Ellipsis,
                style = (+themeTextStyle { h5 }).withOpacity(0.87f))

Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第18张图片

可以看到,设置了 maxLinesoverflow 之后,超出部分就截断处理了,不会影响到整个布局样式。

Compose 布局实时预览

从 Android Studio 4.0 开始,提供了在 IDE 中预览 composable 函数的功能,不用像以前那样,要先下载一个模拟器,然后将 app 状态模拟器上,运行 app 才能看到效果。但是有一个限制,那就是 composable 函数不能有参数满足下面两个条件:

  • 函数没有参数

  • 在函数前面添加 @Preview 注解

预览效果图如下:

Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第19张图片

当布局改变了之后,顶部会出现一个导航条,显示预览已经过期,点击 build&Refresh 就可以刷新预览。

这真的是一个非常棒的功能,像其他声明式布局,如 React 、flutter 是没有这个功能的,布局了之后,要重新运行才能看到效果,虽然可以热启动,但是还是没有这个预览来得直接。还有一个非常厉害的地方是,compose 的预览可以同时预览多个 composable 函数。效果如下:

Android Jetpack Compose 最全上手指南 | 开发者说·DTalk_第20张图片

总结

Jetpack Compose 目前还是试验版,所以还存在很多问题,还不能现在将其用于商业项目中,但是这并不能妨碍我们学习和体验它,声明式 UI 框架近年来飞速发展,React 为声明式 UI 奠定了坚实基础并。Flutter 的发布将声明式 UI 的思想成功带到移动端开发领域,Apple 和 Google 分别先后发布了自己的声明式 UI 框架 SwiftUI 和 Jetpack Compose,以后,原生 UI 布局,声明式可能将会是主流。


长按右侧二维码

查看更多开发者精彩分享

"开发者说·DTalk" 面向中国开发者们征集 Google 移动应用 (apps & games) 相关的产品/技术内容。欢迎大家前来分享您对移动应用的行业洞察或见解、移动开发过程中的心得或新发现、以及应用出海的实战经验总结和相关产品的使用反馈等。我们由衷地希望可以给这些出众的中国开发者们提供更好展现自己、充分发挥自己特长的平台。我们将通过大家的技术内容着重选出优秀案例进行谷歌开发技术专家 (GDE) 的推荐。

 

 点击屏末 |  | 即刻报名参与 "开发者说·DTalk" 

 


你可能感兴趣的:(Android Jetpack Compose 最全上手指南 | 开发者说·DTalk)