敏銳的讀者可能已經注意到我們上面對 BarChart.lerp 的定義中存在潛在的效率低下問題。我們建立摺疊的 Bar 實例只是為了將它們作為參數提供給 Bar.lerp,並且對於動畫參數 t 的每個值都會重複發生這種情況。以每秒 60 幀的速度,即使對於相對較短的動畫,這也可能意味著大量 Bar 實例被饋送到垃圾收集器。有一些替代方案:
通過在 Bar 類別中只建立一次摺疊的 Bar 實例,而不是在每次調用 collapsed 時都建立一次,可以重複使用它們。這種方法在這裡有效,但並不普遍適用。
動畫可能很漂亮且流暢,但對使用者來說仍然會感到困惑。為什麼?因為它沒有保留語義。它將代表產品類別 B 的圖形元素轉換為代表類別 C 的圖形元素,而 C 的圖形元素則移動到其他位置。僅僅因為 2016 年的 B 恰好繪製在 2017 年的 C 後來出現的相同位置並不意味著前者應該變形為後者。相反,2016 年的 B 應該消失,2016 年的 C 應該向左移動並變形為 2017 年的 C,而 2017 年的 D 應該出現在它的右側。我們可以使用書中最古老的演算法之一來實現這種混合:合併排序列表。
@override Widget build(BuildContext context) { returnnew Scaffold( body: new Center( child: new Text('Data set: $dataSet'), ), floatingActionButton: new FloatingActionButton( onPressed: _refreshData, tooltip: 'Refresh', child: new Icon(Icons.refresh), ), ); } }
儲存變更,然後重新啟動應用程式。您可以從終端機執行此操作,方法是按 R 鍵。此「完全重新啟動」操作會捨棄應用程式狀態,然後重建 UI。對於在程式碼變更後現有應用程式狀態仍然有效的情況,可以按 r 鍵進行「熱重載」,這只會重建 UI。IntelliJ IDEA 也有一個 Flutter 外掛,提供與 Dart 編輯器整合的相同功能:
_tween = new Tween(begin: 50.0, end: 50.0); _animation = _tween.animate(_controller);
}
void _refreshData() { setState(() { _tween = new Tween(begin: _tween.end, end: new Random().nextInt(101).toDouble()); _controller.forward(from: 0.0); }); }
@override Widget build(BuildContext context) { returnnew Scaffold( body: new Center( child: new CustomPaint( size: new Size(200.0, 200.0), painter: new BarChartPainter(_animation.value), // Use _animation.value directly )), floatingActionButton: new FloatingActionButton(
onPressed: _refreshData, tooltip: 'Refresh', child: new Icon(Icons.refresh), ), ); }
// ... dispose method remains the same
}
classBarChartPainterextendsCustomPainter{ finaldouble dataSet; // Now takes a double BarChartPainter(this.dataSet);
@override void paint(Canvas canvas, Size size) { final paint = new Paint() ..color = Colors.blue[400] ..style = PaintingStyle.fill; canvas.drawRect( new Rect.fromPoints( new Offset(0.0, size.height - dataSet.toDouble()), // Convert to double if needed new Offset(size.width, size.height), ), paint, ); }
_barTween = new BarTween(begin: new Bar(height:50.0), end: new Bar(height:50.0)); _animation = _barTween.animate(_controller);
}
void _refreshData() { setState(() {
_barTween = new BarTween( begin: _barTween.end, end: new Bar(height: new Random().nextInt(101).toDouble()));
_controller.forward(from: 0.0);
}); }
@override Widget build(BuildContext context) { returnnew Scaffold( body: new Center( child: new CustomPaint( size: new Size(200.0, 200.0), painter: new BarChartPainter(_animation.value), // Pass the Bar object )), floatingActionButton: new FloatingActionButton( onPressed: _refreshData, tooltip: 'Refresh', child: new Icon(Icons.refresh), ), ); }