您好,登錄后才能下訂單哦!
在上一篇文章:Flutter進階—實現動畫效果(一)的最后,我們說到需要一個處理程序混亂的概念。在這一篇文章中,我們會引入補間,它是構建動畫代碼的一個非常簡單的概念,主要作用是用面向對象的方法替代之前面向過程的方法。tween是一個值,它描述了其他值的空間中的兩個點之間的路徑,比如條形圖的動畫值從0運行到1。
補間在Dart中表示類型為Tween的對象
abstract class Tween<T> { final T begin; final T end; Tween(this.begin, this.end); T lerp(double t); }
術語lerp來自計算機圖形學領域,是線性插值(作為名詞)和線性內插(作為動詞)的縮寫。參數t是動畫值,補間應該從begin(當t為0時)到end(當t為1時)。
FlutterSDK的Tween類與Dart非常相似,但是一個支持變化begin和end的具體類。我們可以使用單個Tween來整理代碼,用于處理條形圖高度。
import 'package:flutter/material.dart'; import 'package:flutter/animation.dart'; import 'dart:math'; void main() { runApp(new MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'Flutter Demo', home: new MyHomePage(), ); } } class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() => new _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin { final random = new Random(); int dataSet = 50; AnimationController animation; Tween<double> tween; @override void initState() { super.initState(); animation = new AnimationController( duration: const Duration(milliseconds: 300), vsync: this ); // Tween({T begin, T end }):創建tween(補間) tween = new Tween<double>(begin: 0.0, end: dataSet.toDouble()); animation.forward(); } @override void dispose() { animation.dispose(); super.dispose(); } void changeData() { setState(() { dataSet = random.nextInt(100); tween = new Tween<double>( /* @override T evaluate( Animation<double> animation ) 返回給定動畫的當前值的內插值 當動畫值分別為0.0或1.0時,此方法返回begin和end */ begin: tween.evaluate(animation), end: dataSet.toDouble() ); animation.forward(from: 0.0); }); } @override Widget build(BuildContext context) { return new Scaffold( body: new Center( child: new CustomPaint( size: new Size(200.0, 100.0), /* Animation<T> animate( Animation<double> parent ) 返回一個由給定動畫驅動的新動畫,但它承擔由該對象確定的值 */ painter: new BarChartPainter(tween.animate(animation)) ) ), floatingActionButton: new FloatingActionButton( onPressed: changeData, child: new Icon(Icons.refresh), ), ); } } class BarChartPainter extends CustomPainter { static const barWidth = 10.0; BarChartPainter(Animation<double> animation) : animation = animation, super(repaint: animation); final Animation<double> animation; @override void paint(Canvas canvas, Size size) { final barHeight = animation.value; final paint = new Paint() ..color = Colors.blue[400] ..style = PaintingStyle.fill; canvas.drawRect( new Rect.fromLTWH( size.width-barWidth/2.0, size.height-barHeight, barWidth, barHeight ), paint ); } @override bool shouldRepaint(BarChartPainter old) => false; }
我們使用Tween將條形高度動畫終點包裝在一個值中,它完全與AnimationController和CustomPainter進行接口,因為Flutter框架現在會在每個動畫時間點上標記CustomPaint進行重繪,而不是將整個MyHomePage子樹標記為重構、重新布局和重繪。這些都是顯示的改進,但是,補間的概念不止如此,它提供了組織我們的想法和代碼的結構。
回到我們的代碼,我們需要一個Bar類型和一個BarTween來動畫化它。我們將與bar相關的類提取到bar.dart文件中,放到main.dart同級目錄下。
import 'package:flutter/material.dart'; import 'package:flutter/animation.dart'; import 'dart:ui' show lerpDouble; class Bar { Bar(this.height); final double height; static Bar lerp(Bar begin, Bar end, double t) { return new Bar(lerpDouble(begin.height, end.height, 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 { static const barWidth = 10.0; BarChartPainter(Animation<Bar> animation) : animation = animation, super(repaint: animation); final Animation<Bar> animation; @override void paint(Canvas canvas, Size size) { final bar = animation.value; final paint = new Paint() ..color = Colors.blue[400] ..style = PaintingStyle.fill; canvas.drawRect( new Rect.fromLTWH( size.width-barWidth/2.0, size.height-bar.height, barWidth, bar.height ), paint ); } @override bool shouldRepaint(BarChartPainter old) => false; }
我們遵循FlutterSDK的慣例來定義Bar類的靜態方法BarTween.lerp。DartSDK中沒有double.lerp,所以我們使用dart:ui包中的lerpDouble函數來達到同樣的效果。
現在我們的應用程序可以用條形圖重新顯示。
import 'package:flutter/material.dart'; import 'package:flutter/animation.dart'; import 'dart:math'; import 'bar.dart'; void main() { runApp(new MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'Flutter Demo', home: new MyHomePage(), ); } } class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() => new _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin { final random = new Random(); AnimationController animation; BarTween tween; @override void initState() { super.initState(); animation = new AnimationController( duration: const Duration(milliseconds: 300), vsync: this ); tween = new BarTween(new Bar(0.0), new Bar(50.0)); animation.forward(); } @override void dispose() { animation.dispose(); super.dispose(); } void changeData() { setState(() { tween = new BarTween( tween.evaluate(animation), new Bar(100.0 * random.nextDouble()), ); animation.forward(from: 0.0); }); } @override Widget build(BuildContext context) { return new Scaffold( body: new Center( child: new CustomPaint( size: new Size(200.0, 100.0), painter: new BarChartPainter(tween.animate(animation)) ) ), floatingActionButton: new FloatingActionButton( onPressed: changeData, child: new Icon(Icons.refresh), ), ); } }
未完待續。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。