您好,登錄后才能下訂單哦!
在本篇文章開始前,我們先來回顧一下之前我們都做了哪些事情。在第一篇文章中,我們在動畫值更改時調用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版本。
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文件,讓我們的應用程序可以重新顯示。
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); }); } // ... } }
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。