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 {@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进阶—实现动画效果(二)相关推荐
- Flutter进阶—实现动画效果(三)
在上一篇文章:Flutter进阶-实现动画效果(二)的最后,我们实现了一个控件,其中包含各种布局和状态处理控件.以及使用自定义的动画感知绘图代码绘制单个Bar的控件.还有一个浮动按钮控件,用于启动条形 ...
- Flutter进阶—实现动画效果(四)
在上一篇文章:Flutter进阶-实现动画效果(三)中,实现了一个随机高度.颜色的条形.这一篇文章我们会实现多个条形,同样是随机高度.颜色. 首先在bar.dart中创建BarChart类,并使用固定 ...
- Flutter进阶—实现动画效果(一)
上一篇文章我们了解了Flutter的动画基础:Flutter进阶-解析动画,这一篇文章我们就来实现一个图表的动画效果. 首先,我们需要创建一个新项目myapp,然后把main.dart的内容替换成下面 ...
- Flutter进阶—实现动画效果(八)
通过学习前面的文章,我们现在终于能为更复杂的图表制作动画效果了[手动斜眼笑].接着上一篇文章讲,如果公司的产品销往全国各地,那么我们的图表要展示的内容就需要加上地区.我们可以使用堆叠条形图来试试效果, ...
- Flutter进阶—实现动画效果(十)
前面的两篇文章[动画效果(八).动画效果(九)]中,我们只需要统计产品和地区,如果现在增加一个统计项目--销售渠道,那么使用之前的堆叠条形图和分组条形图都不适合.我们可以将两者结合,使用分组+堆叠条形 ...
- Flutter进阶—实现动画效果(七)
我们假设一种情况,如果应用程序使用条形图显示给定年份的产品类别的销售额,用户可以选择另一年,然后该应用程序将动画到该年的条形图.如果产品类别在两年内是相同的,或者恰好是相同的,除了在其中一个图表中右侧 ...
- Flutter进阶—实现动画效果(五)
在本篇文章开始前,我们先来回顾一下之前我们都做了哪些事情.在第一篇文章中,我们在动画值更改时调用double lerpDouble(num a, num b, double t)重新绘制条形.在第二篇 ...
- Flutter进阶—实现动画效果(九)
在上一篇文章中,我们实现了统计每个产品和地区的销售额,如果现在需要统计每个产品和地区所占市场份额的百分比,那么使用堆叠条形图是不合适的,我们可以使用分组条形图,因为它可以同时在两个类别维度上进行定量比 ...
- Flutter进阶—实现动画效果(六)
在上一篇文章中,我们之前对BarChart.lerp的定义并不是高效的,我们正在创建的Bar实例,仅作为Bar.lerp的参数给出,并且针对动画参数t的每个值重复出现.每秒60帧,这意味着可能很多Ba ...
最新文章
- 全球物联网产业规模不断扩大 中国市场前景分析
- mysql安装ZIP存档什么意思_关于MySQLzip安装常见报错解决方案!
- Objective-C property属性解析
- B-Tree与B+Tree的区别
- JSI2性能测试报告
- 点击页面元素,这个Vite插件竟然帮我打开了Vue组件文件!超级好用!
- 项目中需要总结的内容
- easyUI学习笔记二
- PowerDesigner 导入sql脚本到MySQL乱码问题
- php打包mysql_PHP封装MySQL的单例
- linux下keepalived+nginx的负载均衡搭建
- js原生attachEvent与addEventListener的用法
- 第二次作业—熟悉使用工具
- msu文件无法运行_如何打开msu文件
- GBDT(MART) 迭代决策树入门教程 | 简介 写的非常好!!
- 2017百度之星程序设计大赛 - 资格赛
- JS函数传参、作用域
- 《Dreamweaver CS6 完全自学教程》笔记 第十三章:Dreamweaver 中的 HTML 代码
- p56 p57 p58
- python绘制花朵图案_Python实现平行坐标图的绘制(plotly)方式
热门文章
- PyTorch 学习笔记(七):PyTorch的十个优化器
- ~~堆优化版dijkstra
- Jupyter Notebook——夏侯南溪常用的快捷键
- SQL语句关联查询,UNION ALL用法,结果中查询
- ODrive踩坑(三)AS5047P磁编码器的ABI接口
- 【VUE】npm run dev b报错 “'webpack-dev-server' 不是内部或外部命令,也不是可运行的程序 或批处理文件。”
- 同行压力(兼谈敏捷团队,绩效管理,自组织团队)
- 【100题】第三十二 数组、规划
- 04_(终结版)通过App实现对数据库的增删改
- 前端工具 git笔记