当前位置:   article > 正文

Jetpack Compose 实现鸿蒙引力加载 Loading_jetpack compose 实现loading加载动画

jetpack compose 实现loading加载动画

前言

这是鸿蒙的引力加载动效果,一个小卫星绕着一个上下移动的主星在公转,似乎很简单

效果图

Step 1 : 绘制主星

Compose 给我们提供了丰富的 canvas 绘制 api ,绘制一个圆不多说:

  1. Canvas(modifier = Modifier.align(Alignment.Center)) {
  2. drawCircle(
  3. color = Color.Gray, radius = 50f, style = Stroke(width = 10f)
  4. )
  5. }

然后给主星增加上下移动动画,我们需要使用无限循环动画来实现,使用 infinitRepeatable 轻轻松松:

  1. val infiniteTransition = rememberInfiniteTransition()
  2. val offsetY by infiniteTransition.animateFloat(
  3. initialValue = 0f,
  4. targetValue = 5f,
  5. animationSpec = infiniteRepeatable(
  6. animation = keyframes {
  7. durationMillis = 15000f at 010f at 7250f at 1500
  8. }
  9. )
  10. )
  11. Canvas(
  12. modifier = Modifier
  13. .align(Alignment.Center)
  14. .offset(y = LocalDensity.current.run { offsetY.toDp() }) // 使用动画
  15. ) {
  16. ...
  17. }

看看效果:

Step 2 : 绘制卫星

观察原型图,可以发现卫星的运动轨迹是围绕一个椭圆进行旋转往复运动,这样在视觉上可以以后立体的感觉。如图:

使用 Path 描述椭圆路径

如果需要让目标沿着一个特殊的轨迹进行运动的话,使用 path 动画还是比较方便的。

  1. Canvas(
  2. modifier = Modifier.align(Alignment.Center)
  3. ) {
  4. val path = Path()
  5. path.addOval(Rect(-75f, -35f, 75f, 35f))
  6. rotate(-20f) {
  7. // *坑点1,需要旋转画布来实现斜向椭圆
  8. }
  9. }
  10. }
  11. }

坑点 1 出现 :绘制 api 只能绘制横着的或者竖着的椭圆(椭圆的两个定点在x/y轴上),不能绘制斜的,我们需要通过几何变换来实现

在椭圆 path 上绘制卫星

现在我们已经有了斜向椭圆的 path , 接着通过一个神奇的工具PathMeasure,我们可以的到 path 的有用信息。

pathMeasure 的 getPosTan 方法是用来获取坐标点的,我们提供两个数组分别保存pos 和 tan。

其中pos参数是获取Path指定distance位置的坐标点,也是就指图中的A点,而tan参数是指圆心点:

  1. val animatePer by infiniteTransition.animateFloat(initialValue = 0f,
  2. targetValue = 1f,
  3. animationSpec = infiniteRepeatable(animation = keyframes {
  4. durationMillis = 1300
  5. 0f at 0
  6. 1f at 1300
  7. }
  8. ))
  9. val pathMeasure = android.graphics.PathMeasure()
  10. val pos = FloatArray(2)
  11. val tan = FloatArray(2)
  12. path.addOval(Rect(-75f, -35f, 75f, 35f))
  13. rotate(-20f) {
  14. pathMeasure.setPath(path.asAndroidPath(), true) // * 坑点2 compose下PathMeasure并没有获取位置的方法
  15. pathMeasure.getPosTan(pathMeasure.length * animatePer, pos, tan)
  16. ...
  17. }

坑点 2 :由于在compose下PathMeasure并没有获取位置的方法,所以我们使用android.graphics.PathMeasure(),然后path也需要转换成 android.graphics.Path

同时,我们准备一个控制进度的动画,使用pathMeasure.length * animatePer动态获取到整个path的所有点的坐标。

尝试1:drawPoint来实现

在我们已经得到path上得所有坐标之后,我们将坐标变成一个drawpoint的坐标来绘制出来,compose的drawpoint比较麻烦,这里我们使用原生的canvas来绘制更加方便:

  1. val paint = Paint().asFrameworkPaint().apply {
  2. isAntiAlias = truestrokeWidth = 25f
  3. color = android.graphics.Color.GRAY
  4. strokeCap = android.graphics.Paint.Cap.ROUND
  5. style = android.graphics.Paint.Style.STROKE
  6. }
  7. // 通过 drawIntoCanvas可以获取原生的 canvas
  8. drawIntoCanvas {
  9. it.nativeCanvas.drawPoint(pos[0], pos[1], paint)
  10. }

可以看到,已经有个模样啦,但是仔细观察原素材,可以发现卫星并不是一个简单的点,而且有一个拖尾效果:

尝试2:drawArc实现

我们可以沿着path绘制一段弧形,并给弧形增加渐变来模拟卫星的拖尾效果,同样的这里用到了原生的canvasapi ( 用compose的也可以 )。

另外为了避免内存抖动,我们使用 drawWithCache 将 path 对象的创建放在其中

有些时候我们绘制一些比较复杂的UI效果时,不希望当 Recompose 发生时所有绘画所用的所有实例都重新构建一次(类似Path),这可能会产生内存抖动。在 Compose 中我们一般能够想到使用 remember 进行缓存,然而我们所绘制的作用域是 DrawScope 并不是 Composable,所以无法使用 remember,那我们该怎么办呢?drawWithCache 提供了这个能力。
  1. val paint = Paint().asFrameworkPaint()
  2. Spacer(modifier = Modifier
  3. .align(Alignment.Center)
  4. .drawWithCache {
  5. val path = Path()
  6. val pathMeasure = android.graphics.PathMeasure()
  7. val pos = FloatArray(2)
  8. val tan = FloatArray(2)
  9. onDrawBehind {
  10. path.addOval(Rect(-75f, -35f, 75f, 35f))
  11. rotate(-20f) {
  12. pathMeasure.setPath(path.asAndroidPath(), true)
  13. pathMeasure.getPosTan(pathMeasure.length * animatePer, pos, tan)
  14. paint.apply {
  15. isAntiAlias = true
  16. strokeWidth = 25f
  17. strokeCap = android.graphics.Paint.Cap.ROUND
  18. style = android.graphics.Paint.Style.STROKE
  19. shader = android.graphics.RadialGradient(
  20. pos[0],
  21. pos[1],
  22. 80f,
  23. android.graphics.Color.parseColor("#666466"),
  24. android.graphics.Color.parseColor("#e5e3e5"),
  25. Shader.TileMode.CLAMP
  26. )
  27. }
  28. drawIntoCanvas {
  29. it.nativeCanvas.drawArc(
  30. RectF(-80f, -20f, 80f, 20f),
  31. (atan2(pos[1], pos[0])) * 180 / PI.toFloat(),
  32. 20f,
  33. false,
  34. paint
  35. )
  36. }
  37. }
  38. }
  39. })

坑点 3 :绘制圆弧需要用到角度知识,因为我们已经通过pathMeasure得到了椭圆上的点的x,y,所以我们可以通过反三角函数获取 startAngle,并且注意需要使用 atan2 而不是 atan

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/306029
推荐阅读
相关标签
  

闽ICP备14008679号