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; Tween tween; @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( Animation animation ) 返回给定动画的当前值的内插值 当动画值分别为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), /* Animation animate( Animation parent ) 返回一个由给定动画驱动的新动画,但它承担由该对象确定的值 */ painter:newBarChartPainter(tween.animate(animation)) ) ), floatingActionButton:newFloatingActionButton( onPressed:changeData, child:newIcon(Icons.refresh), ), ); } } classBarChartPainterextendsCustomPainter{ staticconstbarWidth=10.0; BarChartPainter(Animation animation) :animation=animation, super(repaint:animation); finalAnimation animation; @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(Animation animation) :animation=animation, super(repaint:animation); finalAnimation animation; @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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。