
涟漪老孟导读:此篇文章是 Flutter 动画系列文章第五篇,本文介绍2个自定义动画:涟漪和雷达扫描效果。
实现涟漪动画效果如下:
此动画通过 CustomPainter 绘制配合 AnimationController 动画控制实现,定义动画控制部分:
class WaterRipple extends StatefulWidget { final int count; final color color; const WaterRipple({Key key,this.count = 3,this.color = const color(0xFF0080ff)}) : super(key: key); @overrIDe _WaterRippleState createState() => _WaterRippleState();}class _WaterRippleState extends State<WaterRipple> with SingleTickerProvIDerStateMixin { AnimationController _controller; @overrIDe voID initState() { _controller = AnimationController(vsync: this,duration: Duration(milliseconds: 2000)) ..repeat(); super.initState(); } @overrIDe voID dispose() { _controller.dispose(); super.dispose(); } @overrIDe Widget build(BuildContext context) { return AnimatedBuilder( animation: _controller,builder: (context,child) { return CustomPaint( painter: WaterRipplePainter(_controller.value,count: Widget.count,color: Widget.color),); },); }}count 和 color 分别代表水波纹的数量和颜色。
WaterRipplePainter 定义如下:
class WaterRipplePainter extends CustomPainter { final double progress; final int count; final color color; Paint _paint = Paint()..style = PaintingStyle.fill; WaterRipplePainter(this.progress,{this.count = 3,this.color = const color(0xFF0080ff)}); @overrIDe voID paint(Canvas canvas,Size size) { double radius = min(size.wIDth / 2,size.height / 2); for (int i = count; i >= 0; i--) { final double opacity = (1.0 - ((i + progress) / (count + 1))); final color _color = color.withOpacity(opacity); _paint..color = _color; double _radius = radius * ((i + progress) / (count + 1)); canvas.drawCircle( Offset(size.wIDth / 2,size.height / 2),_radius,_paint); } } @overrIDe bool shouldRepaint(CustomPainter oldDelegate) { return true; }}重点是 paint 方法,根据动画进度计算颜色的透明度和半径。
使用如下:
class WaterRipplePage extends StatelessWidget { @overrIDe Widget build(BuildContext context) { return Scaffold( body: Center( child: Container(height: 200,wIDth: 200,child: WaterRipple())),); }}雷达扫描实现雷达扫描效果:
此效果分为两部分:中间的 logo 图片和扫描部分。
中间的 logo 图片中间的 logo 图片边缘有阴影效果,像是太阳发光一样,实现:
Container( height: 70.0,wIDth: 70.0,decoration: Boxdecoration( color: colors.grey,image: decorationImage( image: Assetimage('assets/images/logo.png')),shape: BoxShape.circle,BoxShadow: [ BoxShadow( color: colors.white.withOpacity(.5),blurRadius: 5.0,spreadRadius: 3.0,),]),)扫描定义雷达扫描的动画控制器:
class RadarVIEw extends StatefulWidget { @overrIDe _RadarVIEwState createState() => _RadarVIEwState();}class _RadarVIEwState extends State<RadarVIEw> with SingleTickerProvIDerStateMixin { AnimationController _controller; Animation<double> _animation; @overrIDe voID initState() { _controller = AnimationController(vsync: this,duration: Duration(seconds: 5)); _animation = Tween(begin: .0,end: pi * 2).animate(_controller); _controller.repeat(); super.initState(); } @overrIDe voID dispose() { _controller.dispose(); super.dispose(); } @overrIDe Widget build(BuildContext context) { return AnimatedBuilder( animation: _animation,child) { return CustomPaint( painter: RadarPainter(_animation.value),); }}RadarPainter 定义如下:
class RadarPainter extends CustomPainter { final double angle; Paint _bgPaint = Paint() ..color = colors.white ..strokeWIDth = 1 ..style = PaintingStyle.stroke; Paint _paint = Paint()..style = PaintingStyle.fill; int circleCount = 3; RadarPainter(this.angle); @overrIDe voID paint(Canvas canvas,Size size) { var radius = min(size.wIDth / 2,size.height / 2); canvas.drawline(Offset(size.wIDth / 2,size.height / 2 - radius),Offset(size.wIDth / 2,size.height / 2 + radius),_bgPaint); canvas.drawline(Offset(size.wIDth / 2 - radius,Offset(size.wIDth / 2 + radius,_bgPaint); for (var i = 1; i <= circleCount; ++i) { canvas.drawCircle(Offset(size.wIDth / 2,radius * i / circleCount,_bgPaint); } _paint.shader = ui.GradIEnt.sweep( Offset(size.wIDth / 2,[colors.white.withOpacity(.01),colors.white.withOpacity(.5)],[.0,1.0],TileMode.clamp,.0,pi / 12); canvas.save(); double r = sqrt(pow(size.wIDth,2) + pow(size.height,2)); double startAngle = atan(size.height / size.wIDth); Point p0 = Point(r * cos(startAngle),r * sin(startAngle)); Point px = Point(r * cos(angle + startAngle),r * sin(angle + startAngle)); canvas.translate((p0.x - px.x) / 2,(p0.y - px.y) / 2); canvas.rotate(angle); canvas.drawArc( Rect.fromCircle( center: Offset(size.wIDth / 2,radius: radius),pi / 12,true,_paint); canvas.restore(); } @overrIDe bool shouldRepaint(CustomPainter oldDelegate) { return true; }}将两者结合在一起:
class RadarPage extends StatelessWidget { @overrIDe Widget build(BuildContext context) { return Scaffold( backgroundcolor: color(0xFF0F1532),body: Stack( children: [ positioned.fill( left: 10,right: 10,child: Center( child: Stack(children: [ positioned.fill( child: RadarVIEw(),positioned( child: Center( child: Container( height: 70.0,decoration: Boxdecoration( color: colors.grey,image: decorationImage( image: Assetimage('assets/images/logo.png')),BoxShadow: [ BoxShadow( color: colors.white.withOpacity(.5),) ],)); }}交流老孟Flutter博客地址(330个控件用法):http://laomengit.com
欢迎加入Flutter交流群(微信:laomengit)、关注公众号【老孟Flutter】:
以上是内存溢出为你收集整理的【Flutter 实战】自定义动画-涟漪和雷达扫描全部内容,希望文章能够帮你解决【Flutter 实战】自定义动画-涟漪和雷达扫描所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)