Jetpack Compose 是Google发布的一个Android原生现代UI工具包,它彻底采用Kotlin编写,可使用Kotlin语言的所有特性,能够帮助你轻松、快速的构建高质量的Android应用程序。若是你还不了解Jetpack Compose是什么?建议你读一下我前面的2篇文章:php
Android Jetpack Compose 最全上手指南java
Jetpack Compose,不止是一个UI框架!android
去年的Google IO 大会上,Google宣布了Jetpack Compose的面世,可是在去年11月份,它才发布第一个预览版-Developer Preview1,此后,基本保持每两周发布一个小版本,到如今,半年的时间过去了,中间发布了十多个小版本,今天,终于迎来了重大更新,Developer Preview2 发布了。web
Jetpack Compose Developer Preview1发布后,开发者最关心的几个问题是,没有Compose版本的RecyclerView、Constriantlayout、动画等一系列问题。这些问题在Preview2都解决了。面试
固然,从Preview1 到如今发布的Preview2,变化很是大,甚至不少API都已经变了,有的属性或者类的增长或者删除。具体的变换化太多,就不在这里一一讲解,感兴趣的能够看看官方的每一个小版本的更新日志。今天就带你们一块儿看看PreView2增长的一些重磅功能。bash
好戏开场了!微信
首先,说一下Modifier(修改器),在Preview1版本,就已经有了modifier,不过使用的地方很少,而且对于它的定位比较模糊,使人困惑,由于modifier能干的事儿,经过组合函数也能作到。可是咱们发现了一件事,例如,要在Compose函数中增长padding的时候,会产生大量的嵌套,由于要给嵌套一个容器才能设置padding,所以,如今将不少功能都移动到了Modifier,它如今使用很是普遍,能够修饰一个元素、一个布局或者一些其余行为。如何使用Modifier?先来看一个例子:app
首先,咱们写一个Compose函数(即Compose组件),展现一张图片框架
@Composable
fun Greeting() {
val (shape,setShape) = state<Shape> { CircleShape }
Image(asset = imageResource(R.drawable.androidstudio),
contentScale = ContentScale.Crop )
}
复制代码
图片显示的是原来的尺寸,而后给图片指定一个大小,好比:256dp,此时就须要使用Modifier了。ide
@Composable
fun Greeting() {
val (shape,setShape) = state<Shape> { CircleShape }
Image(asset = imageResource(R.drawable.androidstudio),
contentScale = ContentScale.Crop,
modifier = Modifier.size(256.dp))
}
复制代码
修改后以下,宽高都为256dp。
modifier中有不少能够配的参数,好比,增长一个padding
,将图片裁剪成一个圆形
。
@Composable
fun Greeting() {
val (shape,setShape) = state<Shape> { CircleShape }
Image(asset = imageResource(R.drawable.androidstudio),
contentScale = ContentScale.Crop,
modifier = Modifier.size(256.dp)
.padding(16.dp)
.drawShadow(8.dp,shape = shape)
)
}
复制代码
效果就成了这样:
还能够再圆形头像加一个border
,代码以下:
@Composable
fun Greeting() {
val (shape,setShape) = state<Shape> { CircleShape }
Image(asset = imageResource(R.drawable.androidstudio),
contentScale = ContentScale.Crop,
modifier = Modifier.size(256.dp)
.padding(16.dp)
.drawShadow(8.dp,shape = shape)
.drawBorder(6.dp,MaterialTheme.colors.primary,shape = shape)
)
}
复制代码
效果以下:
还能够同时添加多个border,好比我再增长2个:
@Composable
fun Greeting() {
val (shape,setShape) = state<Shape> { CircleShape }
Image(asset = imageResource(R.drawable.androidstudio),
contentScale = ContentScale.Crop,
modifier = Modifier.size(256.dp)
.padding(16.dp)
.drawShadow(8.dp,shape = shape)
.drawBorder(6.dp,MaterialTheme.colors.primary,shape = shape)
.drawBorder(12.dp,MaterialTheme.colors.secondary,shape = shape)
.drawBorder(18.dp,MaterialTheme.colors.background,shape = shape)
)
}
复制代码
效果就成这样了:
设置点击事件也是再modifier中,好比咱们要在点击这个图片后,改变形状,之前的View可麻烦了,可是Jetpack compose 却很是简单,modifier中增长以下代码:
@Composable
fun Greeting() {
val (shape,setShape) = state<Shape> { CircleShape }
Image(asset = imageResource(R.drawable.androidstudio),
contentScale = ContentScale.Crop,
modifier = Modifier.size(256.dp)
.padding(16.dp)
.drawShadow(8.dp,shape = shape)
.drawBorder(6.dp,MaterialTheme.colors.primary,shape = shape)
.drawBorder(12.dp,MaterialTheme.colors.secondary,shape = shape)
.drawBorder(18.dp,MaterialTheme.colors.background,shape = shape)
.clickable { // 点击事件
setShape(
if(shape == CircleShape)
CutCornerShape(topLeft = 32.dp,bottomRight = 32.dp)
else
CircleShape
)
}
)
}
复制代码
上面的代码中,咱们还增长了判断,若是当前shape是CircleShape
,咱们就改变形状,不然就设置为CircleShape
,效果就是点击图片,形状在这两种效果之间来回切换。
效果以下:
RecyclerView是咱们Android开发中用来展现大数据列表的经常使用组件,它能帮助咱们回收复用视图,有很好的性能体验。在Jetpack Developer PreView1 刚出来的时候,我就在官网或者代码库中找这个组件。很遗憾翻遍了全部资料都每找到,是确实没有,最终只找到了一个叫作VerticalScroller
的组件你。它能够用来展现列表,可是它不是RecyclerView,它相似咱们的ScrollView,也就是说,展现少许数据的列表是能够的,由于它没有复用机制,展现大列表时,内存堪忧,会OOM。
可是在此次的Preview2中,RecyclerView终于被盼来了,组件名字叫作:AdapterList
,它就对应咱们原生Android开发的RecyclerView。之前咱们要写一个列表是很是复杂的,用写xml,Adapter,ViewHolder等,最终还要在Activity/Fragment初始化和绑定数据,很是麻烦。Jetpack Compose中的列表使用则是很是简单,简单到使人发指。来看一下咱们如何展现一个列表:
@Composable
fun generateList(context: Context) {
val list = mutableListOf<String>()
//准备数据
for (i in 1..100) {
list.add(i.toString())
}
AdapterList(data = list) {
Card(
shape = MaterialTheme.shapes.medium,
modifier = Modifier
.preferredSize(context.resources.displayMetrics.widthPixels.dp, 60.dp)
.padding(10.dp)
) {
Box(gravity = ContentGravity.Center) {
ProvideEmphasis(EmphasisAmbient.current.medium) {
Text(
text = it,
style = MaterialTheme.typography.body2
)
}
}
}
Spacer(modifier = Modifier.preferredHeight(10.dp))
}
}
复制代码
看到了没,就是这样几行代码,咱们的列表就完成了,解释一下代码:最开始的准备数据没啥说的,向list中添加了100个数据,而后将数据源传给AdapterList
,列表的每个Item是一个卡片,用的是Card组件,卡片里展现了一个Text文本,最后的Spacer
用来设置item之间的间距,至关于ItemDecoration
,看一下效果:
Constriantlayout
是一个功能很是强大的布局,也是如今Android开发中最受欢迎的布局之一,当Jetpack Compose Preview1版本才出来的时候,不少开发者都有一个疑问,Compose 中该如何使用Constriantlayout
呢?它将如何运做,这确实是个有意思的问题。由于在Jetpack Compose中,全部的组件都是组合函数,获取不到View饮用,如何约束彼此之间的关系确实是一个难题。好在如今这个难题解决了,下面经过几个小例子一块儿来看看Compose中的Constriantlayout
使用。
以下图所示,有两个View,A和B,ViewB在ViewA的右边,顶部和ViewA的底部对齐,如何使用Constriantlayout 描述它们的位置关系?
代码:
@Composable
fun GreetConstraintLayout(context: Context) {
ConstraintLayout(constraintSet = ConstraintSet {
val viewA = tag("ViewTagA").apply {
left constrainTo parent.left
centerVertically()
}
val viewB = tag("ViewTagB").apply {
left constrainTo viewA.right
centerVertically()
top constrainTo viewA.bottom
}
}, modifier = Modifier.preferredSize(context.screenWidth().dp,400.dp).drawBackground(Color.LightGray)) {
Box(
modifier = Modifier.tag("ViewTagA").preferredSize(100.dp, 100.dp),
backgroundColor = Color.Blue,
gravity = ContentGravity.Center
) {
Text(text = "A")
}
Box(
modifier = Modifier.tag("ViewTagB").preferredSize(100.dp, 100.dp),
backgroundColor = Color.Green,
gravity = ContentGravity.Center
) {
Text(text = "B")
}
}
}
复制代码
解释一下上面的代码:在ConstraintSet
中来定义约束,使用Tag来建立一个约束,后面咱们就能够经过这个tag来使用咱们定义的约束,返回的是一个ConstrainedLayoutReference
,ViewA的左边与父组件的左边对齐,垂直居中。ViewB的左边与ViewA的右边对齐,top与ViewA的底部对齐。也垂直居中。
好比ViewB中就是使用ViewA来做为约束条件了。
后面使用的时候,直接用Modifier.tag()
应用约束到组件上。
这还不是最牛逼,还有一个强大的功能是能够在布局约束中添加逻辑,好比:我有一个ViewC 它的位置可能有两种状况:
该怎么写代码?先定一个一个Boolean 变量叫hasFlag
(随便其的名,它的值根据你的业务逻辑某些状况是true,某些状况是false)
val hasFlag = true // 它的值根据你的业务逻辑某些状况是true,某些状况是false
tag("ViewC").apply {
// 根据判断条件改变,约束也改变
left constrainTo (if(hasFlag) viewA else viewB).right
bottom constrainTo viewB.top
}
复制代码
完整代码以下:
@Composable
fun GreetConstraintLayout(context: Context) {
ConstraintLayout(constraintSet = ConstraintSet {
val hasFlag = true // 它的值根据你的业务逻辑某些状况是true,某些状况是false
val viewA = tag("ViewTagA").apply {
left constrainTo parent.left
centerVertically()
}
val viewB = tag("ViewTagB").apply {
left constrainTo viewA.right
centerVertically()
top constrainTo viewA.bottom
}
tag("ViewC").apply {
// 根据判断条件改变,约束也改变
left constrainTo (if(hasFlag) viewA else viewB).right
bottom constrainTo viewB.top
}
}, modifier = Modifier.preferredSize(context.screenWidth().dp,400.dp).drawBackground(Color.LightGray)) {
Box(
modifier = Modifier.tag("ViewTagA").preferredSize(100.dp, 100.dp),
backgroundColor = Color.Blue,
gravity = ContentGravity.Center
) {
Text(text = "A")
}
Box(
modifier = Modifier.tag("ViewTagB").preferredSize(100.dp, 100.dp),
backgroundColor = Color.Green,
gravity = ContentGravity.Center
) {
Text(text = "B")
}
Box(
modifier = Modifier.tag("ViewC").preferredSize(100.dp, 100.dp),
backgroundColor = Color.Red,
gravity = ContentGravity.Center
) {
Text(text = "C")
}
}
}
复制代码
hasFlag=true
效果以下:
hasFlag=false
效果以下:
其余的一些约束布局属性同如今咱们使用的ConstraintLayout
相同,有兴趣的能够去试试。
Jetpack Compose对动画的支持也是开发者很是关心的一个问题,这一小节就看看Compose中,动画的使用,仍是来看一个小例子,先看效果图:
如上,一个简单的属性动画,图片有选中/未选中
两种状态,由未选中->选中
时,有一个正方形->圆形
的动画,而且伴随着alpha
动画。
代码以下:
@Composable
fun GreetAnimate(){
//
val (selected,onValueChange) = state { false }
// radius 变化
val radius = animate(if(selected) 100.dp else 8.dp)
// alpha 动画
val selectAlpha = animate(if(selected) 0.4f else 1.0f)
Surface(shape = RoundedCornerShape(
topLeft = radius,
topRight = radius,
bottomRight = radius,
bottomLeft = radius
)) {
Toggleable(
value = selected,
onValueChange = onValueChange,
modifier = Modifier.ripple()
) {
Image(
asset = imageResource(R.drawable.androidstudio),
modifier = Modifier.preferredSize(200.dp,200.dp),
contentScale = ContentScale.Crop,
alpha = selectAlpha
)
}
}
}
复制代码
动画使用animate
Compose函数来完成,只须要为它提供不一样的target的值,它就能帮你完成之间的变化,一旦动画建立,它就和普通的Compose函数是同样的。
注意一点 :animate
建立的动画是不能被取消的,要建立能够被取消的动画可使用animatedValue
。还有其余两个类似动画函数:animatedFloat
,animatedColor
啥?你说看起来有点熟悉?那可不是嘛,ObjectAnimator
,ValueAnimator
, 你细品,更多关于动画的使用方式这里不展开了,有兴趣的同窗下来本身动手试试。
一门新的语言,一个新的框架,考虑兼容是颇有必要的,就像Kotlin那样,咱们使用Kotlin没必要一会儿重写整个项目,你能够添加一个新的类,一个新的模块中使用Kotlin,由于它们与Java 彻底相互调用。
Jetpack Compose 借鉴了经验,咱们要使用Jetpack Compose,也能够慢慢来,之前的代码不用动,在你的新模块中一点一点的添加,这就涉及到与原来的View的兼容,在Compose中,可使用AndroidView来兼容之前的Views。
好比个人Jetpack Compose 中要使用到Webview,而它自己也没有提供,该如何是好?别担忧,用原来的就行。
首先,建立一个xml文件webview.xml
,里面添加Webview 布局:
<?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">
</WebView>
复制代码
而后写一个compose 函数,使用AndroidView 来加载:
@Composable
fun androidView(){
AndroidView(R.layout.webview){ view ->
val webView = view as WebView
webView.settings.javaScriptEnabled =true
webView.settings.allowFileAccess = true
webView.settings.allowContentAccess = true
webView.loadUrl("https://juejin.im/")
}
}
复制代码
加载了一个原生的Webview,而后在webview中加载了掘金的网址,效果以下:
看一下AndroidView函数签名:
@Composable
// TODO(popam): support modifiers here
fun AndroidView(@LayoutRes resId: Int, postInflationCallback: (View) -> Unit = { _ -> }) {
AndroidViewHolder(
postInflationCallback = postInflationCallback,
resId = resId
)
}
复制代码
接受一个布局文件资源id,和一个回调postInflationCallback
,当View被inflate出来后,会调用这个回调,而后你就能够在回调中使用它了。
可是,注意: 回调一般是在主线程被调用。
总的来讲,此次Developer PreView2 更新比较多,而且不少API发生了变化,增长了一些关键的组件如AdapterList
,ConstraintLayout
,动画组件
等,使用方式也与Preview1有不少不一样。能够来看一下Google关于Jetpack Compose 上的时间表:
可是,要说的是,如今不少API还不是最终版本,能够看到,每个打版本的变化仍是蛮大的,如今仍然不能用在商用项目上。可是就jetpack Compose 自己来讲,我的仍是比较期待的,从上面的时间表就能够看到,大概明年就能出第一个release版本,敬请期待吧!
对了,最新版本的Jetpack Compose 须要Android Studio 4.2以上版本才能使用,想要体验的同窗先安卓Android Studio 4.2 Canary 版本。去官网下载!
小版本日志列表请看:developer.android.com/jetpack/and…
youtobe视频介绍请看:www.youtube.com/watch?v=U5B…
文章首发于公众号:
「 技术最TOP 」
,天天都有干货文章持续更新,能够微信搜索「 技术最TOP 」
第一时间阅读,回复【思惟导图】【面试】【简历】有我准备一些Android进阶路线、面试指导和简历模板送给你