简介

Jetpack Compose是用于构建原生Android界面的新工具包。它是一种声明式的UI布局,其官方声称可简化并加快Android上的界面开发,使用更少的代码、强大的工具和直观的Kotlin API,快速让应用生动而精彩。

官网:https://developer.android.com/jetpack/compose?hl=zh-cn

我这里也写了一个ComposeDemo,可以对照着看:https://github.com/dreamgyf/ComposeDemo

这个Demo实现了:

  • Compose替代传统布局z

  • 网格列表效果,类似于传统布局中的RecyclerView配合GridLayoutManager

  • 在传统View中使用Compose

  • 在Compose中使用传统View

  • 自定义布局

前置工作

使用Jetpack Compose需要先引入一些依赖:

dependencies {implementation 'androidx.core:core-ktx:1.7.0'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.lifecycle:lifecycle-runtime-ktx:2.3.1'implementation 'androidx.activity:activity-compose:1.3.1'debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"//网络图片加载三方库implementation "io.coil-kt:coil-compose:1.4.0"
}

可组合函数

Jetpack Compose是围绕着可组合函数构建起来的,这些函数以程序化方式定义应用的界面,只需描述应用界面的外观并提供数据依赖项,而不必关注界面的构建过程。此类函数有几个要点:

  • 所有可组合函数必须使用@Composable注解修饰
  • 可组合函数可以像正常函数一样接受参数
@Composable
fun Demo(name: String) {Text(text = "Hello, ${name}!")
}
  • 可组合函数内部可以书写正常代码(譬如可以通过if else控制显示的控件)
@Composable
fun Demo(showPic: Boolean) {if (showPic) {Image(painter = painterResource(id = R.drawable.demo),contentDescription = null)}Text(text = "Hello, compose!")
}

单位

Android常用的单位dpsp等,在Compose中以类的形式被定义,使用的方式也很简单,Compose借助了kotlin的扩展属性,扩展了IntDoubleFloat三个基础类,使用方式如下:

//dp
1.dp; 2.3f.dp; 4.5.dp
//sp
1.sp; 2.3f.sp; 4.5.sp

资源

如何在Compose中使用资源呢,可以通过xxxResource方法

//图片资源
fun painterResource(@DrawableRes id: Int): Painter
//尺寸资源
fun dimensionResource(@DimenRes id: Int): Dp
//颜色资源
fun colorResource(@ColorRes id: Int): Color
//字符串资源
fun stringResource(@StringRes id: Int): String
//字体资源
fun fontResource(fontFamily: FontFamily): Typeface

Modifier

ModifierCompose中的布局修饰符,它控制了布局的大小,padding,对齐,背景,边框,裁切,点击等属性,几乎所有的Compose布局都需求这项参数,是Compose布局中的重中之重

这里介绍一些常用的基本属性,文中没列到的属性可以去官网查看:https://developer.android.com/jetpack/compose/modifiers-list?hl=zh-cn

尺寸

  • fillMaxWidthfillMaxHeight相当于xml布局中的match_parent
  • fillMaxSize相当于同时设置了fillMaxWidthfillMaxHeight
  • wrapContentWidthwrapContentHeight相当于xml布局中的wrapContent
  • wrapContentSize相当于同时设置了wrapContentWidthwrapContentHeight
  • widthheight则是设置固定宽高,单位为Dp
  • size相当于同时设置了widthheight
  • weight属性仅在RowColumn的内部作用域中可以使用,相当于传统LinearLayout布局中的weight属性

padding

padding方法有几个重载,这些API很简单,看参数就很容易能明白意思

对齐

align属性,使控件可以在父布局中以一种方式对齐,相当于xml布局中的layout_gravity属性。另外还有alignBy以及alignByBaseline属性可以自行研究

绘图

  • background设置背景,不过不能设置图片,如果想以图片作为背景可以使用Box布局,在底部垫一个Image控件
  • alpha设置透明度
  • clip裁剪内容,这个功能很强大,可以直接将视图裁出圆角,圆形等形状

操作

  • clickable方法,可以设置控件的点击事件回调
  • combinedClickable方法,可以设置控件的点击、双击、长按事件回调
  • selectable方法,将控件配置为可点击,同时可以设置点击事件

滚动

  • horizontalScroll:使控件支持水平滚动
  • verticalScroll:使控件支持垂直滚动

注意事项

Modifier中设置属性的前后顺序是很重要的,譬如想要一个背景为蓝色的圆角布局,需要先设置clip,再设置background,反过来background会超出圆角范围

Spacer

Compose中没有了margin的概念,可以用Spacer替代,Spacer为留白的意思,使用起来也很简单

//水平间隔8dp
Spacer(modifier = Modifier.width(8.dp))

基础布局

Row & Column

这是两个基本布局组件,其中Row为水平布局,Column为垂直布局,他们俩接受的参数相似,其中两个参数为horizontalArrangementverticalAlignment,他们一个表示水平布局方式,一个表示垂直布局方式,他们默认值为STARTTOP,这两个参数用起来就和传统布局的gravity参数一样

Box

Box也是一种基本布局组件,Box布局中的组件是可以叠加的,类似传统布局中的FrameLayout,可以通过contentAlignment参数调整叠加的方式,其默认值为TopStart,叠加到左上角,这个参数也和FrameLayoutgravity参数一样

基础控件

Text

文本控件,对应传统控件TextView,它有以下一些属性

属性 说明
text 文本内容
color 文字颜色
fontSize 文字大小
fontStyle 文本样式(可以设置斜体)
fontWeight 字重(粗体等)
fontFamily 字体
letterSpacing 文字间距
textAlign 文本对齐方式
lineHeight 行高
maxLines 最大行数

Image

图片控件,对应传统控件ImageView,它有以下一些属性

属性 说明
painter 图片内容
contentDescription 无障碍描述(可为null)
alignment 对齐方式
contentScale 缩放方式(和scaleType属性类似)
alpha 透明度

在开发中经常会面对从网络价值图片的情况,这时候可以借助一些第三方库来解决,这里以coil库为例:

  1. 先添加依赖
implementation "io.coil-kt:coil-compose:1.4.0"
  1. 使用
Image(modifier = Modifier.size(68.dp, 68.dp).clip(RoundedCornerShape(6.dp)),contentScale = ContentScale.Crop,painter = rememberImagePainter(picUrl), //使用rememberImagePainter方法填入图片urlcontentDescription = null
)

列表

Compose有两种组件LazyRowLazyColumn,一种水平,一种垂直,对应着传统UI中的RecyclerView,用这些组件可以方便的构建列表视图,它们需要提供一个LazyListScope.()块描述列表项内容

LazyListScopeDSL提供了多种函数来描述列表项:

//用于添加单个列表项
fun item(key: Any? = null, content: @Composable LazyItemScope.() -> Unit)
//用于添加多个列表项
fun items(count: Int,key: ((index: Int) -> Any)? = null,itemContent: @Composable LazyItemScope.(index: Int) -> Unit)
//用于添加多个列表项
fun <T> LazyListScope.items(items: List<T>,noinline key: ((item: T) -> Any)? = null,crossinline itemContent: @Composable LazyItemScope.(item: T) -> Unit
)

示例:

val list = mutableListOf(0, 1, 2, 3, 4)LazyColumn {//增加单个列表项item {Text(text = "First item")}//增加5个列表项items(5) { index ->Text(text = "Item: $index")}//增加5个列表项items(list) { listItem ->Text(text = "Item: $listItem")}//增加单个列表项item {Text(text = "Last item")}
}

可以使用contentPadding为内容添加内边距,使用verticalArrangementhorizontalArrangement,以Arrangement.spacedBy()为列表项之间添加间距

状态

Compose中,数据的更新和传统命令式UI不同,是通过一种可观察类型对象,当一个可观察类型对象发生改变时,这个对象对应观察的部分会发生重组,从而自动更新UI

可观察类型MutableState<T>通常是通过mutableStateOf()函数创建的,这个对象的value发生变化时,对应UI也会跟着随之变化

//这里使用了kotlin的by关键字,是一种代理模式
//如果使用 = 的话,这个对象的类型会发生变化,需要count.value这样使用它的值
//var count = mutableStateOf(0)
var count by mutableStateOf(0)@Composable
fun Demo(count: Int) {Column {Text(text = "count: ${count}")Button(onClick = { addCount() }) {Text(text = "add count")}}
}fun addCount() {//++count.value++count
}@Preview
@Composable
fun Preview() {//当点击Button时,触发点击事件,更新可观察对象count,触发UI重组//Demo(count.value)Demo(count)
}

关于Context

Compose中可以通过LocalContext.current获得当前Context

在传统View中使用Compose

可以在一个传统布局xml中插入一个ComposeView

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:id="@+id/hello_world"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="Hello from XML layout" /><!-- 插入ComposeView --><androidx.compose.ui.platform.ComposeViewandroid:id="@+id/compose_view"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout>

然后在代码中设置这个ComposeView

findViewById<ComposeView>(R.id.compose_view).setContent {Text("Hello Compose!")
}

在Compose中使用传统View

可以使用AndroidView这个composable函数,这个函数接受一个factory参数,这个参数接受一个Context,用于构建传统View,要求返回一个继承自View的对象

@Composable
fun Demo() {Column {Text(text = "Compose Text")AndroidView(factory = { context ->//这里也可以使用LayoutInflater从xml中解析出一个ViewTextView(context).apply {text = "传统TextView"}})}
}

自定义UI

Compose中,如果想要自定义一些简单的UI是很简单的,只需要写一个Composable函数就可以了,我们主要学习一下怎么自定义一些复杂的UI

我们先看一下怎么自定义一个布局,对应着传统UI中的ViewGroup,以一个简单的例子来说,我们自定义一个布局,让其中的子布局呈左上到右下依次排列:

@Composable
fun MyLayout(modifier: Modifier = Modifier, content: @Composable () -> Unit) {Layout(modifier = modifier, content = content) { measurables, constraints ->//测量每个子布局val placeables = measurables.map { measurable ->measurable.measure(constraints)}//设置布局大小为最大可容纳大小layout(constraints.maxWidth, constraints.maxHeight) {var xPosition = 0var yPosition = 0//放置每个子Viewplaceables.forEach { placeable ->placeable.placeRelative(x = xPosition, y = yPosition)//下一个子View的坐标为上一个子View的右下角xPosition += placeable.widthyPosition += placeable.height}}}
}

我们再看一个使用Canvas自定义View的方式,这个更简单,就是画一条水平线:

@SuppressLint("ModifierParameter")
@Composable
fun HorizontalLine(modifier: Modifier = Modifier.fillMaxWidth()) {Canvas(modifier = Modifier.then(modifier), onDraw = {drawLine(color = Color.Black, Offset(0f, 0f), Offset(size.width, 0f), 2f)})
}

我们将两者一起用一下看看效果

@Preview(showBackground = true)
@Composable
fun Preview() {MyLayout {Text(text = "Text1")HorizontalLine(Modifier.width(50.dp))Text(text = "Text2")}
}

其实Compose中的自定义UI的思路和传统自定义View是一样的,只不过需要熟悉Compose中的各种Api才能灵活运用它

Jetpack Compose入门相关推荐

  1. Jetpack Compose入门详解(实时更新)

    Jetpack Compose入门详解 前排提醒 前言(Compose是什么) 1.实战准备 一.优势与缺点 二.前四课 三.标准布局组件 1.Column 2.Row 3.Box 四.xml和com ...

  2. Android原生UI开发框架 《Jetpack Compose入门到精通》最全上手指南

    前言 在去年的Google/IO大会上,亮相了一个全新的 Android 原生 UI 开发框架-Jetpack Compose, 与苹果的SwiftIUI一样,Jetpack Compose是一个声明 ...

  3. 告别XML,Android新声明式UI框架《Jetpack Compose入门到精通》最全开发指南

    什么是Jetpack Compose? Jetpack Compose是Android的新声明式UI框架.长期以来, Android 开发人员习惯于使用带有状态视图的xml编写UI,这些状态视图通过逐 ...

  4. Jetpack Compose入门篇-简约而不简单

    好文推荐: 作者:QiShare Compose简介 Jetpack Compose:利用声明式编程构建Android原生界面(UI)的 工具包 优势 更少的代码.代码量锐减 强大的工具/组件支持 直 ...

  5. 移动开发 Jetpack Compose 组件布局

    Jetpack Compose 是用于构建原生 Android 界面的新工具包.它可简化并加快 Android 上的界面开发,使用更少的代码.强大的工具和直观的 Kotlin API,快速让应用生动而 ...

  6. Jetpack Compose之手写分享页面

    文章目录 前言 一.xml实现 二.Compose实现 1.底部分享组件 a.背景半圆角 b.自定义分享按钮 c.在底部的取消按钮 d.总体 2.二维码分享组件 a.组件居中 b.顶部头像 c.二维码 ...

  7. Android Study Jam 在线答疑第三期:Jetpack Compose 案例实战

    Android Study Jam 火热进行中 感兴趣的小伙伴都上车了吗? 为助力大家打好 Jetpack Compose 基础 我们的第三场 Office Hours 在线答疑 将于 今天上午 10 ...

  8. Jetpack Compose 实战 宝可梦图鉴

    文章目录 前言 实现效果 一.架构介绍 二.一些的功能点的介绍 加载图片并获取主色,再讲主色设置为背景 一个进度缓慢增加的圆形进度条 单Activity使用navigation跳转Compose可组合 ...

  9. Android Jetpack Compose

    Android Jetpack Compose 一.什么是Jetpack Compose 二.关于Jetpack Compase的介绍 Jetpack Compose的特点 Jetpack Compo ...

最新文章

  1. Java中父类构造方法对子类构造方法的影响(不是一句话可以说清的)
  2. java服务端开发 php_PHP使用thrift做服务端开发
  3. 简述JavaME,JavaSE,JavaEE
  4. spring boot中修改默认端口号
  5. 用Ghostscript API将PDF格式转换为图像格式(C#)
  6. datagridview 动态插入图片_挑战一张照片制作动态PPT背景
  7. 首次自动对接!美国离本土载人航天又进一步,SpaceX成功抵达国际空间站
  8. mysql 事务 隔离级别_MySQL的四种事务隔离级别
  9. Hadoop集群下进行集成测试的小策略
  10. css background 一半_CSS---阴阳图
  11. Python 标准库 —— fractions
  12. 微信开发者工具安装使用SVN
  13. HTML5 简介与安装
  14. golang程序员前景怎么样?Python、Java、go语言的优势互比
  15. 一个amp;quot;现象级amp;quot;大数据公司的蜕变
  16. 新建的web项目为什么默认访问index.jsp
  17. 和府捞面全新品牌“小面小酒”在福州开业,下一批新店落地天津、淄博
  18. 恋词题源报刊Unit2
  19. Unity 多重材质球替换、多重材质球特定贴图替换、Materials替换
  20. 中职计算机教师招聘试题库,职业技术学校教师考试题目

热门文章

  1. windows 11 恢复右键传统菜单 <转>
  2. 计算机组成原理中译码器,计算机组成原理课程设计-指令系统及七段译码器设计.doc...
  3. 数据结构实验报告——约瑟夫问题(循环链表)
  4. 神华资产注入预期或被透支
  5. Google挖坑后人埋-ViewBinding(上)
  6. 【浏览器】Chrome (on Mac)
  7. 概率论基础—什么是概率?
  8. 分子生物学词汇(D~F)
  9. table-cell布局
  10. superclass