【Flutter 实战】自定义动画-涟漪和雷达扫描

【Flutter 实战】自定义动画-涟漪和雷达扫描,第1张

概述老孟导读:此篇文章是 Flutter 动画系列文章第五篇,本文介绍2个自定义动画:涟漪和雷达扫描效果。 涟漪 实现涟漪动画效果如下: 此动画通过 CustomPainter 绘制配合 Animatio

老孟导读:此篇文章是 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 实战】自定义动画-涟漪和雷达扫描所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1000427.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-21
下一篇2022-05-21

发表评论

登录后才能评论

评论列表(0条)

    保存