状态动画AnimateAsState
上一篇文章中,学习了动画最基本的AnimationSpec,今天来往上层走,应用这些动画规格。 AnimateAsState是使用最简单的动画,根据一个状态来触发动画,消费即忘,下面一个个来看如何使用和效果展示。
animateFloatAsState
定义:
@Composable
public fun animateFloatAsState(
targetValue: Float,
animationSpec: AnimationSpec<Float> = defaultAnimation,
visibilityThreshold: Float = 0.01f,
label: String = "FloatAnimation",
finishedListener: ((Float) -> Unit)? = null
): State<Float>
参数解释:
- targetValue:目标值,这里是Float类型的目标值。
- animationSpec:动画规格,也就是上一篇文章讲到的动画基础,参考compose动画从底层基础到顶层高级应用(一)动画规格--AnimationSpec
- visibilityThreshold:动画提前结束的阈值,在上一篇中也详细解释过了。
- label:给这个动画打一个标签,调试用。
- finishedListener:动画完成的回调,完成时回调targetValue的值。
使用:
浮点数类型的值,我想到的一般是颜色的alpha值,那么下面就写一个组件颜色透明度变化的动画。
@Preview
@Composable
fun AnimationExample() {
// 使用enable这个状态去控制动画的开始
var enable by remember { mutableStateOf(false) }
// 使用isRunning去记录动画是否运行
var isRunning by remember { mutableStateOf(false) }
// Float类型状态动画,目标值根据enable这个状态去设置对应的值,
// 动画规格使用的是tween动画,持续2秒,
// finishedListener回调触发时更新isRunning状态
val alpha by animateFloatAsState(
targetValue = if (enable) 1f else 0f,
animationSpec = tween(durationMillis = 2000),
finishedListener = {
isRunning = false
}
)
Box(
modifier = Modifier
.fillMaxSize()
.padding(10.dp),
contentAlignment = Alignment.Center
) {
Box(
modifier = Modifier
.padding(top = 150.dp)
.size(100.dp)
.alpha(alpha) //直接在modifier的alpha函数中传入动画状态
.background(Color(0xFF4CAF50))
.align(Alignment.TopCenter)
)
Button(
onClick = {
isRunning = true
enable = !enable //点击按钮时触发enable,继而触发动画
},
modifier = Modifier
.size(width = 120.dp, height = 40.dp)
.align(Alignment.Center),
) {
Text(
text = if (isRunning) "Running" else "Ready",
color = Color.White
)
}
}
}
效果:
接下来的几个不同类型的状态动画我就不一一展示代码,不然太长了,用法都是一样的,有特殊的会详细解释。
animateDpAsState
Dp类型的动画,一般用于高度或者宽度等场景。
定义:
@Composable
public fun animateDpAsState(
targetValue: Dp,
animationSpec: AnimationSpec<Dp> = dpDefaultSpring,
label: String = "DpAnimation",
finishedListener: ((Dp) -> Unit)? = null
): State<Dp>
animateSizeAsState
Size类型动画,Size(width, height)
定义:
@Composable
public fun animateSizeAsState(
targetValue: Size,
animationSpec: AnimationSpec<Size> = sizeDefaultSpring,
label: String = "SizeAnimation",
finishedListener: ((Size) -> Unit)? = null
): State<Size>
animateOffsetAsState
偏移量类型的动画,Offset(x, y)
定义:
@Composable
public fun animateOffsetAsState(
targetValue: Offset,
animationSpec: AnimationSpec<Offset> = offsetDefaultSpring,
label: String = "OffsetAnimation",
finishedListener: ((Offset) -> Unit)? = null
): State<Offset>
animateRectAsState
矩形类型的动画,Rect封装了Offset,Size等类型。
定义:
@Composable
public fun animateRectAsState(
targetValue: Rect,
animationSpec: AnimationSpec<Rect> = rectDefaultSpring,
label: String = "RectAnimation",
finishedListener: ((Rect) -> Unit)? = null
): State<Rect>
animateIntAsState
Int类型的动画
定义:
@Composable
public fun animateIntAsState(
targetValue: Int,
animationSpec: AnimationSpec<Int> = intDefaultSpring,
label: String = "IntAnimation",
finishedListener: ((Int) -> Unit)? = null
): State<Int>
animateIntOffsetAsState
IntOffset类型的动画
定义:
@Composable
public fun animateIntOffsetAsState(
targetValue: IntOffset,
animationSpec: AnimationSpec<IntOffset> = intOffsetDefaultSpring,
label: String = "IntOffsetAnimation",
finishedListener: ((IntOffset) -> Unit)? = null
): State<IntOffset>
animateIntSizeAsState
IntSize类型的动画
定义:
@Composable
public fun animateIntSizeAsState(
targetValue: IntSize,
animationSpec: AnimationSpec<IntSize> = intSizeDefaultSpring,
label: String = "IntSizeAnimation",
finishedListener: ((IntSize) -> Unit)? = null
): State<IntSize>
animateColorAsState
颜色类型动画。
定义:
@Composable
public fun animateColorAsState(
targetValue: Color,
animationSpec: AnimationSpec<Color> = colorDefaultSpring,
label: String = "ColorAnimation",
finishedListener: ((Color) -> Unit)? = null
): State<Color>
animateValueAsState
自定义类型动画,前面都是系统提供的封装好的类型,那么如果遇到自定义的类型,就需要使用到这个函数了。
定义:
@Composable
public fun <T, V : AnimationVector> animateValueAsState(
targetValue: T,
typeConverter: TwoWayConverter<T, V>,
animationSpec: AnimationSpec<T> = remember { spring() },
visibilityThreshold: T? = null,
label: String = "ValueAnimation",
finishedListener: ((T) -> Unit)? = null
): State<T>
参数:
- typeConverter:这是跟前面不一样的参数,需要传递的是将自定义类型和AnimationVector之间进行转换的逻辑。
AnimationVector:
compose动画会将不同的类型向量化,才能通过数学模型进行动画处理,AnimationVector有四个子类,分别是AnimationVector1D, AnimationVector2D, AnimationVector3D 和AnimationVector4D,也就是提供了4个维度的转化。 前面提到的不同类型动画内部其实都是使用的animateValueAsState函数做的封装,比如第一个Float类型的动画,内部代码是:
return animateValueAsState(
targetValue,
Float.VectorConverter, //typeConverter传入的是Float内定义的转换函数
resolvedAnimSpec,
visibilityThreshold,
label,
finishedListener
)
// Float只有一维,因此使用的是AnimationVector1D,像Offset使用的是AnimationVector2D,颜色是AnimationVector4D
public val Float.Companion.VectorConverter: TwoWayConverter<Float, AnimationVector1D>
get() = FloatToVector
private val FloatToVector: TwoWayConverter<Float, AnimationVector1D> = TwoWayConverter({ AnimationVector1D(it) }, { it.value })
使用:
这里我自定义一个CustomSize类型的动画,包含宽和高,和系统提供的animateSizeAsState做比较看看有没有区别。
// 自定义类型
data class CustomSize(
val width: Float,
val height: Float
)
// 编写类型转换逻辑,使用到二维类型AnimationVector2D
val converter = TwoWayConverter<CustomSize, AnimationVector2D>(
convertToVector = { AnimationVector2D(it.width, it.height) },
convertFromVector = { CustomSize(it.v1, it.v2) }
)
@Preview
@Composable
fun AnimationExample() {
var enable by remember { mutableStateOf(false) }
var isRunning by remember { mutableStateOf(false) }
// 这是系统提供的Size类型动画函数
val size by animateSizeAsState(
targetValue = if (enable) {
Size(100f, 100f)
} else {
Size(200f, 200f)
},
animationSpec = tween(durationMillis = 2000),
finishedListener = {
isRunning = false
}
)
// 这是自定义类型的动画函数,也是控制大小的
val customSize by animateValueAsState(
typeConverter = converter,
targetValue = if (enable) {
CustomSize(width = 100f, height = 100f)
} else {
CustomSize(width = 200f, height = 200f)
},
animationSpec = tween(2000),
finishedListener = {
isRunning = false
}
)
Box(
modifier = Modifier
.fillMaxSize()
.padding(10.dp),
contentAlignment = Alignment.Center
) {
Row(
modifier = Modifier
.fillMaxWidth()
.align(Alignment.TopCenter)
.padding(top = 40.dp),
horizontalArrangement = Arrangement.Center
) {
Box(
modifier = Modifier
.padding(end = 10.dp)
//这个方块使用系统的size
.size(size.width.dp, size.height.dp)
.background(Color(0xFF4CAF50))
)
Box(
modifier = Modifier
//这个方块使用自定义的CustomSize
.size(customSize.width.dp, customSize.height.dp)
.background(Color(0xFF00BCD4))
)
}
Button(
onClick = {
isRunning = true
enable = !enable
},
modifier = Modifier
.size(width = 120.dp, height = 40.dp)
.align(Alignment.Center),
) {
Text(
text = if (isRunning) "Running" else "Ready",
color = Color.White
)
}
}
}
效果:
从动图中可以看到自定义CustomSize的和系统封装的Size是一样的效果,去看源码也可以发现系统的代码和我们写的基本一样。
今日学习到此为止,喜欢的可以点赞收藏,:)