开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情
使用过view中的MotionLayout的同学都知道MotionLayout能轻松的让你做出一些复杂的动画,想使用compose的同学肯定也很疑惑我可不可以在compose里面也使用motionlayout呢,答案是可以的。
在Compose中需要依赖的library是:
implementation "androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha04"
下面先看一个简单的例子:
上面是一个简单的动画例子,点击按钮之后开始做Motion动画,其实就是简单的将图标从左移动到右边,下面看看demo的代码:
var enableMotion by remember {
mutableStateOf(false)
}
val buttonAnimationProgress by animateFloatAsState(
// specifying target value on below line.
targetValue = if (enableMotion) 1f else 0f,
// on below line we are specifying
// animation specific duration's 1 sec
animationSpec = tween(1000)
)
// A surface container using the 'background' color from the theme
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
val motionScene = remember {
resources.openRawResource(R.raw.motion_scene).readBytes().decodeToString()
}
Column(modifier = Modifier.fillMaxSize().padding(top = 50.dp)) {
MotionLayout(motionScene = MotionScene(
content = motionScene
), progress = buttonAnimationProgress) {
Box(modifier = Modifier.layoutId("box").background(Color.Blue)){
Icon(modifier = Modifier.layoutId("icon").background(Color.Red),imageVector = Icons.Default.Home, contentDescription = null)
}
}
Button(onClick = { enableMotion = !enableMotion }) {
Text(text = "do motion",color= Color.White)
}
}
}
我们先看MotionLayout的使用,这个里面有两个变量,一个是motionScene一个是progress,motionScene主要定义和动画相关的信息,progress定义了一个移动的动画属性。MotionLayout大致分为两种创建方式一种就是我们上面使用的,看看定义:
inline fun MotionLayout(
motionScene: MotionScene,
progress: Float,
debug: EnumSet<MotionLayoutDebugFlags> = EnumSet.of(MotionLayoutDebugFlags.NONE),
modifier: Modifier = Modifier,
optimizationLevel: Int = Optimizer.OPTIMIZATION_STANDARD,
crossinline content: @Composable (MotionLayoutScope.() -> Unit),
)
MotionScene可以是一个json文件,下面看看例子中json文件的写法:
{
ConstraintSets : {
start : {
box : {
width : 90,
height : 90,
start : ['parent','start'],
end : ['parent','end'],
top : ['parent','top'],
bottom : ['parent','bottom']
},
icon : {
width : 90,
height : 90,
start : ['box','start',7],
top : ['box','top',16],
custom : {
corner : 50
}
}
},
end : {
box : {
width : 90,
height : 90,
start : ['parent','start',300],
end : ['parent','end'],
top : ['parent','top'],
bottom : ['parent','bottom']
},
icon : {
width : 90,
height : 90,
top : ['box','top',16],
left : ['box','left'],
right : ['box','right'],
custom : {
corner : 25
}
},
}
},
Transitions : {
default : {
from : 'start',
end : 'end',
pathMotionArc : 'startHorizontal',
duration : 900,
onSwipe : {
anchor : 'box',
maxVelocity : 4.2,
maxAccel : 3,
direction : 'start',
side : 'end',
mode : 'velocity'
},
KeyFrames : {
KeyAttributes : [
{
target : ['icon'],
frames : [0,100]
}
]
}
}
}
}
大家可以看到,其实就是定义了一个ConstraintSets,定义了它开始的状态以及结束的状态,当然还有一些transitions的属性,对于每一个控件还可以自定义属性。 另外一种创建的方式如下:
inline fun MotionLayout(
start: ConstraintSet,
end: ConstraintSet,
transition: androidx.constraintlayout.compose.Transition? = null,
progress: Float,
debug: EnumSet<MotionLayoutDebugFlags> = EnumSet.of(MotionLayoutDebugFlags.NONE),
modifier: Modifier = Modifier,
optimizationLevel: Int = Optimizer.OPTIMIZATION_STANDARD,
crossinline content: @Composable MotionLayoutScope.() -> Unit
)
感觉和上面的差不多,只是把start和end以及transition几个参数分开了。如果大家使用过view中的MotionLayout那么属于compose中的基本也就很快了,其实原理上基本差不多。