在上一篇文章: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 {@overrideWidget 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;@overridevoid 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();}@overridevoid dispose() {animation.dispose();super.dispose();}void changeData() {setState(() {dataSet = random.nextInt(100);tween = new Tween<double>(/*@overrideT evaluate(Animation<double> animation)返回给定动画的当前值的内插值当动画值分别为0.0或1.0时,此方法返回begin和end*/begin: tween.evaluate(animation),end: dataSet.toDouble());animation.forward(from: 0.0);});}@overrideWidget 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;@overridevoid 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);}@overridebool 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);@overrideBar 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;@overridevoid 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);}@overridebool 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 {@overrideWidget 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;@overridevoid 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();}@overridevoid 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);});}@overrideWidget 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),),);}
}

未完待续~~~

Flutter进阶—实现动画效果(二)相关推荐

  1. Flutter进阶—实现动画效果(三)

    在上一篇文章:Flutter进阶-实现动画效果(二)的最后,我们实现了一个控件,其中包含各种布局和状态处理控件.以及使用自定义的动画感知绘图代码绘制单个Bar的控件.还有一个浮动按钮控件,用于启动条形 ...

  2. Flutter进阶—实现动画效果(四)

    在上一篇文章:Flutter进阶-实现动画效果(三)中,实现了一个随机高度.颜色的条形.这一篇文章我们会实现多个条形,同样是随机高度.颜色. 首先在bar.dart中创建BarChart类,并使用固定 ...

  3. Flutter进阶—实现动画效果(一)

    上一篇文章我们了解了Flutter的动画基础:Flutter进阶-解析动画,这一篇文章我们就来实现一个图表的动画效果. 首先,我们需要创建一个新项目myapp,然后把main.dart的内容替换成下面 ...

  4. Flutter进阶—实现动画效果(八)

    通过学习前面的文章,我们现在终于能为更复杂的图表制作动画效果了[手动斜眼笑].接着上一篇文章讲,如果公司的产品销往全国各地,那么我们的图表要展示的内容就需要加上地区.我们可以使用堆叠条形图来试试效果, ...

  5. Flutter进阶—实现动画效果(十)

    前面的两篇文章[动画效果(八).动画效果(九)]中,我们只需要统计产品和地区,如果现在增加一个统计项目--销售渠道,那么使用之前的堆叠条形图和分组条形图都不适合.我们可以将两者结合,使用分组+堆叠条形 ...

  6. Flutter进阶—实现动画效果(七)

    我们假设一种情况,如果应用程序使用条形图显示给定年份的产品类别的销售额,用户可以选择另一年,然后该应用程序将动画到该年的条形图.如果产品类别在两年内是相同的,或者恰好是相同的,除了在其中一个图表中右侧 ...

  7. Flutter进阶—实现动画效果(五)

    在本篇文章开始前,我们先来回顾一下之前我们都做了哪些事情.在第一篇文章中,我们在动画值更改时调用double lerpDouble(num a, num b, double t)重新绘制条形.在第二篇 ...

  8. Flutter进阶—实现动画效果(九)

    在上一篇文章中,我们实现了统计每个产品和地区的销售额,如果现在需要统计每个产品和地区所占市场份额的百分比,那么使用堆叠条形图是不合适的,我们可以使用分组条形图,因为它可以同时在两个类别维度上进行定量比 ...

  9. Flutter进阶—实现动画效果(六)

    在上一篇文章中,我们之前对BarChart.lerp的定义并不是高效的,我们正在创建的Bar实例,仅作为Bar.lerp的参数给出,并且针对动画参数t的每个值重复出现.每秒60帧,这意味着可能很多Ba ...

最新文章

  1. 全球物联网产业规模不断扩大 中国市场前景分析
  2. mysql安装ZIP存档什么意思_关于MySQLzip安装常见报错解决方案!
  3. Objective-C property属性解析
  4. B-Tree与B+Tree的区别
  5. JSI2性能测试报告
  6. 点击页面元素,这个Vite插件竟然帮我打开了Vue组件文件!超级好用!
  7. 项目中需要总结的内容
  8. easyUI学习笔记二
  9. PowerDesigner 导入sql脚本到MySQL乱码问题
  10. php打包mysql_PHP封装MySQL的单例
  11. linux下keepalived+nginx的负载均衡搭建
  12. js原生attachEvent与addEventListener的用法
  13. 第二次作业—熟悉使用工具
  14. msu文件无法运行_如何打开msu文件
  15. GBDT(MART) 迭代决策树入门教程 | 简介 写的非常好!!
  16. 2017百度之星程序设计大赛 - 资格赛
  17. JS函数传参、作用域
  18. 《Dreamweaver CS6 完全自学教程》笔记 第十三章:Dreamweaver 中的 HTML 代码
  19. p56 p57 p58
  20. python绘制花朵图案_Python实现平行坐标图的绘制(plotly)方式

热门文章

  1. PyTorch 学习笔记(七):PyTorch的十个优化器
  2. ~~堆优化版dijkstra
  3. Jupyter Notebook——夏侯南溪常用的快捷键
  4. SQL语句关联查询,UNION ALL用法,结果中查询
  5. ODrive踩坑(三)AS5047P磁编码器的ABI接口
  6. 【VUE】npm run dev b报错 “'webpack-dev-server' 不是内部或外部命令,也不是可运行的程序 或批处理文件。”
  7. 同行压力(兼谈敏捷团队,绩效管理,自组织团队)
  8. 【100题】第三十二 数组、规划
  9. 04_(终结版)通过App实现对数据库的增删改
  10. 前端工具 git笔记