Transition 初体验
先看下面这个代码 ,其实作用很简答 便是一个点击时刻 触发一段动画罢了
一边改size 一边改圆角巨细
setContent {
var big by remember {
mutableStateOf(false)
}
var bigTransition = updateTransition(big, label = "big")
//animateDpAsState
val size by bigTransition.animateDp(label = "size") {
if (it) 100.dp else 50.dp
}
val corner by bigTransition.animateDp(label = "corner") {
if (it) 50.dp else 0.dp
}
Box(modifier = Modifier
.size(size)
.clip(RoundedCornerShape(corner))
.background(Color.Green)
.clickable {
big = !big
})
}
有人就要问了 你这个动画作用 咱们用animateDpAsState 相同能够完成啊,代码还比你这个少一点,为啥要用这个?
咱们能够看看 假如用animateDpAsState 来写 代码是啥相同的
setContent {
var big by remember {
mutableStateOf(false)
}
val size by animateDpAsState (
if (big) 100.dp else 50.dp
)
val corner by animateDpAsState (
if (big) 0.dp else 50.dp
)
Box(modifier = Modifier
.size(size)
.clip(RoundedCornerShape(corner))
.background(Color.Green)
.clickable {
big = !big
})
}
显着看的出来 animateDpAsState 写法反而更简略。
两者差异或者说为啥要推 Transition 这个东西?
首要第一, 当你想做多个动画的时候,比方上文中的例子,我要改动多个状况,animateDpAsState 这一个函数就代表了一个协程, 你有10个状况要改动 那便是10个, 可是假如用Transition 来办理,则不管你有多少个状况需要改动,则都只要一个协程,性能上 Transition 会有一点优势
第二 Transition 能够更好的预览作用
看下图 几个红框的地方 其实便是Transition 写法中的label, 这种预览方法能够很便利的让咱们调试动画作用 这是animateDpAsState 没有的
第三 当你办理一组动画的时候,实际上 Transition 的写法 更好,这点纯属个人代码审美了
AnimatedVisibility
来看下这个动画,看名字也能知道 这应该是个操控可见性的动画
setContent {
Column() {
var show by remember {
mutableStateOf(true)
}
AnimatedVisibility(show) {
Box(
modifier = Modifier
.height(100.dp)
.width(100.dp)
.background(color = Color.Red)
)
}
Button(onClick = {
show = !show
},) {
Text(text = "change")
}
}
}
能够看下作用
你会发现,这个可见性动画有点神奇啊,他的表现形式 是垂直方向弹性,跟咱们的布局Column是一一对应的
来看下代码 就一目了然了
相同咱们也看一下其他的完成
看到这 咱们其实能够下一个定论 便是 AnimatedVisibility 本质上便是 Transition 动画
能够着重关注下 下面的 动画是怎样完成的?+ 号啥意思
首要便是这个sealed class了, 不知道sealed class的同学 能够自己搜下, 暂时了解成他便是一个interface即可
这儿能够看下他的完成就只要一个impl罢了
恩,实际上动画的表现形式便是在这个class中来决议了
fade 其实便是一个 淡入淡出的作用 能够看下参数类型
再看下这个slide 他其实便是定义你这个收支的作用 是从哪个方位延伸而来,属所以延伸动画
AnimatedVisibility(show, enter = slideIn(tween(2500)) {
IntOffset(-50,-50)
}) {
Box(
modifier = Modifier
.height(100.dp)
.width(100.dp)
.background(color = Color.Red)
)
}
这个lambda参数 便是定义 你是从哪个方位 扩展而来
能够看下作用
这儿或许有人觉得 你这个作用太傻了,正常人不会写的这么丑 我想要的是 跟我的view 自己巨细相关的
其实这个动画是有个默认值能够取到原始巨细的
所以咱们能直接取到view的宽高 那么全部就很和谐了
略微改一下
IntOffset(-it.width,-it.height)
作用我们能够自己跑一下 看看,这儿就不重复演示了
再来看一下 第三个参数ChangeSize
AnimatedVisibility(show, enter = expandIn(tween(2500), expandFrom = Alignment.TopStart,
initialSize = { IntSize(0, 0) })) {
Box(
modifier = Modifier
.height(100.dp)
.width(100.dp)
.background(color = Color.Red)
)
}
看下作用:
这儿或许有人会问,这个作用和slidein 有点相似?有啥差异?
其实差异大了啊,这个changesize 本质上是 裁切变换的view的巨细,你看这个change的方位就能看出来 他是逐步到下面的
而咱们的slideIn,也便是slide动画 他的巨细是一会儿就固定到view的原始巨细,然后view从一个方位 挪过来罢了。
这俩本质上不是一个东西,仅仅视觉上的作用比较相似罢了
最后一个参数 Scale 挺简略的,我们自己写一个试试吧,留意Scale 也是不改动view巨细的,改动的仅仅view绘制的那部分巨细。
+ 号是怎样回事?
其实要害便是在plus函数的完成了, 咱们能够简略的了解为 A+B 就等于 A.plus(B)
仔细看这个 plus函数的完成 其实便是 假如A有 那就用A的,假如A没有 就用B的
组合,留意是组合不是相加,然后 组合成一个新的TransitionData
CrossFade
setContent {
Column() {
var show by remember {
mutableStateOf(true)
}
Crossfade(show){
if (it) {
Box(
modifier = Modifier
.height(50.dp)
.width(50.dp)
.background(color = Color.Blue)
)
} else {
Box(
modifier = Modifier
.height(100.dp)
.width(100.dp)
.background(color = Color.Red)
)
}
}
Button(
onClick = {
show = !show
},
) {
Text(text = "change")
}
}
}
这个很简略,其实便是2个view的改变 改变的过程中有动画
参数和上一个小节里边简直一摸相同,不过多介绍了
AnimatedContent
这个东西和crossfade 作用差不多 能够操控多个view展现的,只不过他操控的粒度更细致。
setContent {
Column() {
var show by remember {
mutableStateOf(true)
}
AnimatedContent(show) {
if (it) {
Box(
modifier = Modifier
.background(Color.Red)
.width(100.dp)
.height(100.dp)
)
} else {
Box(
modifier = Modifier
.background(Color.Green)
.width(50.dp)
.height(50.dp)
)
}
}
Button(
onClick = {
show = !show
},
) {
Text(text = "AnimatedContent change")
}
var show2 by remember {
mutableStateOf(true)
}
Crossfade(show2, modifier = Modifier.padding(top = 100.dp)) {
if (it) {
Box(
modifier = Modifier
.background(Color.Red)
.width(100.dp)
.height(100.dp)
)
} else {
Box(
modifier = Modifier
.background(Color.Green)
.width(50.dp)
.height(50.dp)
)
}
}
Button(
onClick = {
show2 = !show2
},
) {
Text(text = "Crossfade change2")
}
}
}
能够看下 animatedContent和crossfade的差异
-
crossfade 两个一起改变,进入和退出的动画是一起进行,而animatedContent则是有先后顺序 简略来说cf 是并行的,而animatecontent则是串行的
-
AnimateContent的 size改变是 动态的,逐渐改变的,而Crossfade 则是突兀的,瞬间改变的
我们能够多领会一下gif图 或者自己写个demo
能够看下代码 显着的deley时刻和 fadeout的动画时刻是一一对应的
能够看下这个要害参数 contenttransform
这个target和init 2个参数便是 进入和退出的作用,很简略, sizeTransform 是 巨细的突变作用 而 targetContentZIndex 则是 z轴的优先级,也便是 到底是你隐瞒我还是我隐瞒你
不过 一般咱们写动画也不会写到这个targetContentZIndex
所以把握了这些参数信息 你很容易就能够定制自己想要的动画作用了
比方下面这种写法,便是等一个动画完毕了 别的一个动画才开端 很简略的写法
AnimatedContent(show, transitionSpec = { fadeIn(tween(3000)) with fadeOut(tween(3000,3000)) }) {
总结
整个Compose的动画 到这儿就差不多完毕了,全体感觉上写法比传统view 上 要简略不少,多写几个demo 试试不同参数的作用 也就能快速把握了。别的引荐下扔物线大佬的compose课 讲的很好