我想要为笔画路径设置动画,但我找不到分段动画的方法。如何在 jetpack compose 中从起点开始以 0.7 的路径分段在画布下方绘制?
Canvas(modifier = Modifier.size(150.dp)) {
val path = Path()
val width: Float = size.width
val height: Float = size.height
path.apply {
moveTo(width / 2, height / 5)
cubicTo(
5 * width / 14, 0f,
0f, height / 15,
width / 28, 2 * height / 5
)
cubicTo(
width / 14, 2 * height / 3,
3 * width / 7, 5 * height / 6,
width / 2, height
)
cubicTo(
4 * width / 7, 5 * height / 6,
13 * width / 14, 2 * height / 3,
27 * width / 28, 2 * height / 5
)
cubicTo(
width, height / 15,
9 * width / 14, 0f,
width / 2, height / 5
)
}
drawPath(color = Color.Red, path = path, style = Stroke(8f))
}
您可以使用
val pathMeasure by remember { mutableStateOf(PathMeasure()) }
进行操作,并使用 设置开始和结束距离
pathWithProgress.reset()
pathMeasure.setPath(path, forceClosed = false)
pathMeasure.getSegment(
startDistance = 0f,
stopDistance = pathMeasure.length * progress,
pathWithProgress,
startWithMoveTo = true
)
下面的代码片段从路径的 0.7f 开始,根据进度,我使用了滑块进行演示,但它可以很容易地进行动画化,可以绘制到完整的路径长度。
结果
代码
@Preview
@Composable
private fun Test() {
var progress1 by remember {
mutableStateOf(0.7f)
}
val transition: InfiniteTransition = rememberInfiniteTransition(label = "heart animation")
// Infinite phase animation for PathEffect
val progress2 by transition.animateFloat(
initialValue = 0f,
targetValue = 1f,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 1500,
easing = FastOutSlowInEasing
),
), label = "heart animation"
)
// This is the progress path which wis changed using path measure
val pathWithProgress by remember {
mutableStateOf(Path())
}
// using path
val pathMeasure by remember { mutableStateOf(PathMeasure()) }
val path = remember {
Path()
}
Column(
Modifier
.fillMaxSize()
.padding(20.dp)
) {
Text(text = "Progress1: $progress1")
Slider(
value = progress1,
onValueChange = { progress1 = it },
valueRange = 0.7f..1f
)
Canvas(modifier = Modifier.size(150.dp)) {
val width: Float = size.width
val height: Float = size.height
if (path.isEmpty) {
path.apply {
moveTo(width / 2, height / 5)
cubicTo(
5 * width / 14, 0f,
0f, height / 15,
width / 28, 2 * height / 5
)
cubicTo(
width / 14, 2 * height / 3,
3 * width / 7, 5 * height / 6,
width / 2, height
)
cubicTo(
4 * width / 7, 5 * height / 6,
13 * width / 14, 2 * height / 3,
27 * width / 28, 2 * height / 5
)
cubicTo(
width, height / 15,
9 * width / 14, 0f,
width / 2, height / 5
)
}
}
pathWithProgress.reset()
pathMeasure.setPath(path, forceClosed = false)
pathMeasure.getSegment(
startDistance = 0f,
stopDistance = pathMeasure.length * progress1,
pathWithProgress,
startWithMoveTo = true
)
drawPath(color = Color.Red, path = pathWithProgress, style = Stroke(8f))
pathWithProgress.reset()
pathMeasure.setPath(path, forceClosed = false)
pathMeasure.getSegment(
startDistance = 0f,
stopDistance = pathMeasure.length * progress2,
pathWithProgress,
startWithMoveTo = true
)
translate(left = 500f) {
drawPath(color = Color.Blue, path = pathWithProgress, style = Stroke(8f))
}
}
}
}