Flutter进阶之实现动画效果(二)
在上一篇文章:Flutter进阶—实现动画效果(一)的最后,我们说到需要一个处理程序混乱的概念。在这一篇文章中,我们会引入补间,它是构建动画代码的一个非常简单的概念,主要作用是用面向对象的方法替代之前面向过程的方法。tween是一个值,它描述了其他值的空间中的两个点之间的路径,比如条形图的动画值从0运行到1。
补间在Dart中表示类型为Tween的对象
abstractclassTween{ finalTbegin; finalTend; Tween(this.begin,this.end); Tlerp(doublet); }
术语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';
voidmain(){
runApp(newMyApp());
}
classMyAppextendsStatelessWidget{
@override
Widgetbuild(BuildContextcontext){
returnnewMaterialApp(
title:'FlutterDemo',
home:newMyHomePage(),
);
}
}
classMyHomePageextendsStatefulWidget{
@override
_MyHomePageStatecreateState()=>new_MyHomePageState();
}
class_MyHomePageStateextendsStatewithTickerProviderStateMixin{
finalrandom=newRandom();
intdataSet=50;
AnimationControlleranimation;
Tweentween;
@override
voidinitState(){
super.initState();
animation=newAnimationController(
duration:constDuration(milliseconds:300),
vsync:this
);
//Tween({Tbegin,Tend}):创建tween(补间)
tween=newTween(begin:0.0,end:dataSet.toDouble());
animation.forward();
}
@override
voiddispose(){
animation.dispose();
super.dispose();
}
voidchangeData(){
setState((){
dataSet=random.nextInt(100);
tween=newTween(
/*
@override
Tevaluate(
Animationanimation
)
返回给定动画的当前值的内插值
当动画值分别为0.0或1.0时,此方法返回begin和end
*/
begin:tween.evaluate(animation),
end:dataSet.toDouble()
);
animation.forward(from:0.0);
});
}
@override
Widgetbuild(BuildContextcontext){
returnnewScaffold(
body:newCenter(
child:newCustomPaint(
size:newSize(200.0,100.0),
/*
Animationanimate(
Animationparent
)
返回一个由给定动画驱动的新动画,但它承担由该对象确定的值
*/
painter:newBarChartPainter(tween.animate(animation))
)
),
floatingActionButton:newFloatingActionButton(
onPressed:changeData,
child:newIcon(Icons.refresh),
),
);
}
}
classBarChartPainterextendsCustomPainter{
staticconstbarWidth=10.0;
BarChartPainter(Animationanimation)
:animation=animation,
super(repaint:animation);
finalAnimationanimation;
@override
voidpaint(Canvascanvas,Sizesize){
finalbarHeight=animation.value;
finalpaint=newPaint()
..color=Colors.blue[400]
..style=PaintingStyle.fill;
canvas.drawRect(
newRect.fromLTWH(
size.width-barWidth/2.0,
size.height-barHeight,
barWidth,
barHeight
),
paint
);
}
@override
boolshouldRepaint(BarChartPainterold)=>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'showlerpDouble;
classBar{
Bar(this.height);
finaldoubleheight;
staticBarlerp(Barbegin,Barend,doublet){
returnnewBar(lerpDouble(begin.height,end.height,t));
}
}
classBarTweenextendsTween{
BarTween(Barbegin,Barend):super(begin:begin,end:end);
@override
Barlerp(doublet)=>Bar.lerp(begin,end,t);
}
classBarChartPainterextendsCustomPainter{
staticconstbarWidth=10.0;
BarChartPainter(Animationanimation)
:animation=animation,
super(repaint:animation);
finalAnimationanimation;
@override
voidpaint(Canvascanvas,Sizesize){
finalbar=animation.value;
finalpaint=newPaint()
..color=Colors.blue[400]
..style=PaintingStyle.fill;
canvas.drawRect(
newRect.fromLTWH(
size.width-barWidth/2.0,
size.height-bar.height,
barWidth,
bar.height
),
paint
);
}
@override
boolshouldRepaint(BarChartPainterold)=>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';
voidmain(){
runApp(newMyApp());
}
classMyAppextendsStatelessWidget{
@override
Widgetbuild(BuildContextcontext){
returnnewMaterialApp(
title:'FlutterDemo',
home:newMyHomePage(),
);
}
}
classMyHomePageextendsStatefulWidget{
@override
_MyHomePageStatecreateState()=>new_MyHomePageState();
}
class_MyHomePageStateextendsStatewithTickerProviderStateMixin{
finalrandom=newRandom();
AnimationControlleranimation;
BarTweentween;
@override
voidinitState(){
super.initState();
animation=newAnimationController(
duration:constDuration(milliseconds:300),
vsync:this
);
tween=newBarTween(newBar(0.0),newBar(50.0));
animation.forward();
}
@override
voiddispose(){
animation.dispose();
super.dispose();
}
voidchangeData(){
setState((){
tween=newBarTween(
tween.evaluate(animation),
newBar(100.0*random.nextDouble()),
);
animation.forward(from:0.0);
});
}
@override
Widgetbuild(BuildContextcontext){
returnnewScaffold(
body:newCenter(
child:newCustomPaint(
size:newSize(200.0,100.0),
painter:newBarChartPainter(tween.animate(animation))
)
),
floatingActionButton:newFloatingActionButton(
onPressed:changeData,
child:newIcon(Icons.refresh),
),
);
}
}
未完待续。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。