服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - Flutter进阶之实现动画效果(五)

Flutter进阶之实现动画效果(五)

2022-07-20 13:12何小有 Android

这篇文章主要为大家详细介绍了Flutter进阶之实现动画效果的第五篇,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

在本篇文章开始前,我们先来回顾一下之前我们都做了哪些事情。在第一篇文章中,我们在动画值更改时调用double lerpDouble(num a, num b, double t)重新绘制条形。在第二篇文章中,我们首先用Tween类帮助我们管理动画值,并重新绘制条形,然后把绘制条形动画相关的类提取到bar.dart文件。在第三篇文章中,我们首先在Bar类中增加颜色的字段,再新建color_palette.dart文件,用于获取颜色值,同时用工厂构造函数Bar.empty和Bar.random分别创建空白Bar实例和随机Bar实例。在第四篇文章中,我们新增了BarChart类,用于创建指定数量的Bar实例列表,并将绘制条形的代码更改为绘制条形图。

接下来,我们为Bar类增加x坐标和宽度属性,然后我们使BarChart支持具有不同列数的图表。我们的新图表将适用于数据集,其中bar i代表某些系列中的第i个值,如产品发布后第i天的销售额。这样的图表涉及0..n个条形,但一个图表的条形数量n可能不同于下一个图表。

比如有两个图表,分别有5个和7个条形。5个条形的表格可以按照之前的方法进行动画化。bars的索引5和6在另一个动画终点没有对方,但是现在我们可以自由地给每个条形自己的位置和宽度,我们可以引入两个不可见的条形来扮演这个角色。视觉上效果是随着动画的进行,bars的索引5和6成长为最终的外观。如果是相反方向的动画,则bars的索引5和6将会减弱或淡入隐形。

复合值之间的线性插值(lerp)通过相应的组件相关联,如果某个组件在一个终点丢失,则在其位置使用一个不可见组件。通常有几种方法来选择不可见的组件,假设我们的产品经理决定使用零宽度、零高度的条形,其x坐标和颜色从其可见对象继承,我们将为Bar添加一个方法来创建给定实例的collapsed版本。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import 'package:flutter/material.dart';
import 'package:flutter/animation.dart';
import 'dart:ui' show lerpDouble;
import 'dart:math';
import 'color_palette.dart';
 
class BarChart {
 final List<Bar> bars;
 
 BarChart(this.bars);
 
 factory BarChart.empty(Size size) {
 return new BarChart(<Bar>[]);
 }
 
 factory BarChart.random(Size size, Random random) {
 const barWidthFraction = 0.75;
 const minBarDistance = 20.0;
 // floor():返回不大于此的最大整数
 final barCount = random.nextInt((size.width/minBarDistance).floor()) + 1;
 final barDistance = size.width / (1+barCount);
 final barWidth = barDistance * barWidthFraction;
 final startX = barDistance - barWidth/2;
 final color = ColorPalette.primary.random(random);
 final bars = new List.generate(
  barCount,
  (i)=> new Bar(
  startX + i * barDistance,
  barWidth,
  random.nextDouble() * size.height,
  color,
  ),
 );
 return new BarChart(bars);
 }
 
 static BarChart lerp(BarChart begin, BarChart end, double t) {
 // max:返回两个数字中较大的一个
 final barCount = max(begin.bars.length, end.bars.length);
 final bars = new List.generate(
  barCount,
  (i) => Bar.lerp(
  // ??:如果为空时取的默认值
  begin._barOrNull(i) ?? end.bars[i].collapsed,
  end._barOrNull(i) ?? begin.bars[i].collapsed,
  t,
  )
 );
 return new BarChart(bars);
 }
 
 Bar _barOrNull(int index) => (index<bars.length ? bars[index] : null);
}
 
class BarChartTween extends Tween<BarChart> {
 BarChartTween(BarChart begin, BarChart end) : super(begin: begin, end: end);
 
 @override
 BarChart lerp(double t) => BarChart.lerp(begin, end, t);
}
 
class Bar {
 Bar(this.x, this.width, this.height, this.color);
 final double x;
 final double width;
 final double height;
 final Color color;
 
 Bar get collapsed => new Bar(x, 0.0, 0.0, color);
 
 static Bar lerp(Bar begin, Bar end, double t) {
 return new Bar(
  lerpDouble(begin.x, end.x, t),
  lerpDouble(begin.width, end.width, t),
  lerpDouble(begin.height, end.height, t),
  Color.lerp(begin.color, end.color, t)
 );
 }
}
 
class BarTween extends Tween<Bar> {
 BarTween(Bar begin, Bar end) : super(begin: begin, end: end);
 
 @override
 Bar lerp(double t) => Bar.lerp(begin, end, t);
}
 
class BarChartPainter extends CustomPainter {
 BarChartPainter(Animation<BarChart> animation)
  : animation = animation,
  super(repaint: animation);
 
 final Animation<BarChart> animation;
 
 @override
 void paint(Canvas canvas, Size size) {
 final paint = new Paint()..style = PaintingStyle.fill;
 final chart = animation.value;
 for(final bar in chart.bars) {
  paint.color = bar.color;
  canvas.drawRect(
  new Rect.fromLTWH(
   bar.x,
   size.height - bar.height,
   bar.width,
   bar.height
  ),
  paint
  );
 }
 }
 
 @override
 bool shouldRepaint(BarChartPainter old) => false;
}

将上述代码整合到我们的应用程序中,包括为此新设置重新定义BarChart.random和BarChart.empty。现在可以合理地使用空白图表来包含空图表零条形,而随机的条形图可以包含所有相同随机颜色的随机数量的条形,并且每个具有随机选择的高度。但是由于位置和宽度现在是Bar定义的一部分,我们需要BarChart.random来指定这些属性。为BarChart.random提供图表Size参数是合理的,可以缓解BarChartPainter.paint的大部分计算。

最后我们需要更新main.dart文件,让我们的应用程序可以重新显示。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
 static const size = const Size(200.0, 100.0);
 // ...
 @override
 void initState() {
 // ...
 tween = new BarChartTween(
  new BarChart.empty(size),
  new BarChart.random(size, random));
 animation.forward();
 }
 // ...
 void changeData() {
 setState(() {
  tween = new BarChartTween(
  tween.evaluate(animation),
  new BarChart.random(size, random),
  );
  animation.forward(from: 0.0);
 });
 }
 // ...
 }
}

Flutter进阶之实现动画效果(五)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/hekaiyou/article/details/72699781

延伸 · 阅读

精彩推荐