显示时执行显示动画,隐藏时执行隐藏动画。
val visible = remember {
mutableStateOf(true)
}
Column(
modifier = Modifier
.size(360.dp)
.padding(10.dp)
) {
Button(onClick = { visible.value = !visible.value }) {
Text("可见性动画")
}
AnimatedVisibility(visible = visible.value) {
Text(text = "床前明月光,疑是地上霜,举头望明月,低头思故乡", modifier = Modifier.size(150.dp)
}
}
val visible = remember {
mutableStateOf(true)
}
Column(
modifier = Modifier
.size(360.dp)
.padding(10.dp)
) {
Button(onClick = { visible.value = !visible.value }) {
Text("可见性动画")
}
AnimatedVisibility(visible = visible.value,
enter = slideIn { IntOffset(400, 400) } + expandIn(),
exit = slideOut { IntOffset(400, 400) } + shrinkOut()) {
Text(
text = "床前明月光,疑是地上霜,举头望明月,低头思故乡", modifier = Modifier.size(150.dp)
)
}
}
val isExpand = remember {
mutableStateOf(true)
}
Column(
modifier = Modifier
.size(360.dp)
.padding(10.dp)
) {
Text(
text = "床前明月光,疑是地上霜,举头望明月,低头思故乡。床前明月光,疑是地上霜,举头望明月,低头思故乡。床前明月光,疑是地上霜,举头望明月,低头思故乡。",
fontSize = 16.sp,
textAlign = TextAlign.Justify,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.animateContentSize(),
maxLines = if (isExpand.value) Int.MAX_VALUE else 2
)
Text(if (isExpand.value) "收起" else "全文", color = Color.Blue, modifier = Modifier.clickable {
isExpand.value = !isExpand.value
})
}
val tabs = Tabs.values()
var position by remember { mutableStateOf(Tabs.ONE) }
Box(modifier = Modifier.padding(paddingValues)) {
Crossfade(targetState = position) { screen ->
when (screen) {
Tabs.ONE -> OnePage()
Tabs.TWO -> TwoPage()
Tabs.THREE -> ThreePage()
Tabs.FOUR -> FourPage()
}
}
}
animateXXXAsState() 函数可以使用:Float、Color、Dp、Size、Bounds、Offset、Rect、Int、IntOffset、IntSize。
var isSmall by remember {
mutableStateOf(true)
}
val size: Dp by animateDpAsState(if (isSmall) 40.dp else 100.dp) {
Log.e("TAG", "尺寸变化:$it")
}
val color: Color by animateColorAsState(if (isSmall) Color.Red else Color.Blue) {
Log.e("TAG", "颜色变化:$it")
}
Column(Modifier.padding(16.dp)) {
Button(onClick = { isSmall = !isSmall }, modifier = Modifier.padding(vertical = 16.dp)) {
Text("修改尺寸")
}
Box(
Modifier
.size(size)
.background(color)
)
}
val ok = remember {
mutableStateOf(false)
}
val color = remember {
Animatable(Color.Red)
}
LaunchedEffect(ok.value) {
color.animateTo(if (ok.value) Color.Yellow else Color.Green)
}
Column {
Box(
Modifier
.size(360.dp)
.background(color.value)
)
Button(onClick = { ok.value = !ok.value }) {
Text("点击")
}
}
在 Compose 中需要使用 updateTransition 组合多个动画。
var boxState: BoxState by remember { mutableStateOf(BoxState.Small) }
val transition = updateTransition(targetState = boxState, label = "transition")
val color by transition.animateColor(label = "color") {
boxState.color
}
val size by transition.animateDp(label = "size") {
boxState.size
}
val offset by transition.animateDp(label = "offset") {
boxState.offset
}
val angle by transition.animateFloat(label = "angle") {
boxState.angle
}
Column {
Button(
onClick = { boxState = !boxState }
) {
Text("hello world")
}
Box(
Modifier
.padding(top = 20.dp)
.rotate(angle)
.size(size)
.offset(x = offset)
.background(color)
)
}
val infiniteTransition = rememberInfiniteTransition()
val color by infiniteTransition.animateColor(
initialValue = Color.Red,
targetValue = Color.Green,
animationSpec = infiniteRepeatable(
animation = tween(1000, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
)
)
Box(
Modifier
.size(360.dp)
.background(color)
)
spring 可在起始值和结束值之间创建基于物理特性的动画。
fun <T> spring(
dampingRatio: Float = Spring.DampingRatioNoBouncy, // 阻尼系数
stiffness: Float = Spring.StiffnessMedium, // 刚度
visibilityThreshold: T? = null
)
val flag = remember {
mutableStateOf(true)
}
val size by animateDpAsState(
targetValue = if (flag.value) 300.dp else 100.dp,
animationSpec = spring(
dampingRatio = Spring.DampingRatioHighBouncy,
stiffness = Spring.StiffnessMedium
)
)
Box(
Modifier
.size(size)
.background(Color.Blue)
.clickable {
flag.value = !flag.value
}
)
tween用来创建使用给定的持续时间、延迟以及缓和曲线配置的tween规范。
fun <T> tween(
durationMillis: Int = DefaultDurationMillis, // 持续时长
delayMillis: Int = 0, // 延迟播放时间
easing: Easing = FastOutSlowInEasing // 缓动曲线
)
val flag = remember {
mutableStateOf(true)
}
val size by animateDpAsState(
targetValue = if (flag.value) 300.dp else 100.dp,
animationSpec = tween(
durationMillis = 5000, easing = LinearEasing
)
)
Box(
Modifier
.size(size)
.background(Color.Blue)
.clickable {
flag.value = !flag.value
}
)
keyframes会根据在动画时长内不同时间戳中指定的快照值添加动画效果。
val flag = remember {
mutableStateOf(true)
}
val size by animateDpAsState(
targetValue = if (flag.value) 300.dp else 100.dp,
animationSpec = keyframes {
durationMillis = 5000
100.dp at 1000 with LinearOutSlowInEasing // for 0-1000 ms
150.dp at 2000 with FastOutLinearInEasing // for 1000-2000 ms
200.dp at 3000 // 2000-3000 ms
}
)
Box(
Modifier
.size(size)
.background(Color.Blue)
.clickable {
flag.value = !flag.value
}
)
repeatable 可以反复执行指定时长的动画。
fun <T> repeatable(
iterations: Int, // 重复次数
animation: DurationBasedAnimationSpec<T>, // 执行动画
repeatMode: RepeatMode = RepeatMode.Restart, // 重复模式
initialStartOffset: StartOffset = StartOffset(0)
)
val flag = remember {
mutableStateOf(false)
}
val size by animateDpAsState(
targetValue = if (flag.value) 300.dp else 100.dp,
animationSpec = repeatable(
iterations = 2,
animation = tween(
durationMillis = 5000, easing = LinearEasing
),
repeatMode = RepeatMode.Reverse
)
)
Box(
Modifier
.size(size)
.background(Color.Blue)
.clickable {
flag.value = !flag.value
}
)
fun <T> infiniteRepeatable(
animation: DurationBasedAnimationSpec<T>,
repeatMode: RepeatMode = RepeatMode.Restart,
initialStartOffset: StartOffset = StartOffset(0)
)
val flag = remember {
mutableStateOf(false)
}
val size by animateDpAsState(
targetValue = if (flag.value) 300.dp else 100.dp,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 5000, easing = LinearEasing
),
repeatMode = RepeatMode.Reverse
)
)
Box(
Modifier
.size(size)
.background(Color.Blue)
.clickable {
flag.value = !flag.value
}
)
val flag = remember {
mutableStateOf(false)
}
val size by animateDpAsState(
targetValue = if (flag.value) 300.dp else 100.dp,
animationSpec = if (flag.value) tween(
durationMillis = 5000,
easing = LinearEasing
) else snap()
)
Box(
Modifier
.size(size)
.background(Color.Blue)
.clickable {
flag.value = !flag.value
}
)