Flutter进阶—实现动画效果(二)
在上一篇文章: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,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',);
}
}
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,painter: new BarChartPainter(tween.animate(animation))
)
),);
}
}
未完待续~~~ (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |