1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 【Flutter 实战】自定义动画-涟漪和雷达扫描

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

时间:2024-07-07 10:18:33

相关推荐

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

老孟导读:此篇文章是 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;@overridevoid initState() {_controller =AnimationController(vsync: this, duration: Duration(milliseconds: 2000))..repeat();super.initState();}@overridevoid dispose() {_controller.dispose();super.dispose();}@overrideWidget build(BuildContext context) {return AnimatedBuilder(animation: _controller,builder: (context, child) {return CustomPaint(painter: WaterRipplePainter(_controller.value,count: widget.count,color: widget.color),);},);}}

countcolor分别代表水波纹的数量和颜色。

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)});@overridevoid 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);}}@overridebool shouldRepaint(CustomPainter oldDelegate) {return true;}}

重点是paint方法,根据动画进度计算颜色的透明度和半径。

使用如下:

class WaterRipplePage extends StatelessWidget {@overrideWidget 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;@overridevoid initState() {_controller =AnimationController(vsync: this, duration: Duration(seconds: 5));_animation = Tween(begin: .0, end: pi * 2).animate(_controller);_controller.repeat();super.initState();}@overridevoid dispose() {_controller.dispose();super.dispose();}@overrideWidget build(BuildContext context) {return AnimatedBuilder(animation: _animation,builder: (context, 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);@overridevoid 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, size.height / 2),Offset(size.width / 2 + radius, size.height / 2), _bgPaint);for (var i = 1; i <= circleCount; ++i) {canvas.drawCircle(Offset(size.width / 2, size.height / 2),radius * i / circleCount, _bgPaint);}_paint.shader = ui.Gradient.sweep(Offset(size.width / 2, size.height / 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, size.height / 2), radius: radius),0,pi / 12,true,_paint);canvas.restore();}@overridebool shouldRepaint(CustomPainter oldDelegate) {return true;}}

将两者结合在一起:

class RadarPage extends StatelessWidget {@overrideWidget 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,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,),]),),),),]),),)],));}}

交流

老孟Flutter博客地址(330个控件用法):

欢迎加入Flutter交流群(微信:laomengit)、关注公众号【老孟Flutter】:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。