Flutter实现WiFi信号动画

461 阅读1分钟

效果如下

ezgif.com-video-to-gif.gif

Widget

class WifiWidget extends StatefulWidget {

  final Color color;

  const WifiWidget({Key? key, required this.color}) : super(key: key);

  @override
  State<StatefulWidget> createState() => _WifiWidgetState();

}

class _WifiWidgetState extends State<WifiWidget> with SingleTickerProviderStateMixin {

  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller =
    AnimationController(vsync: this, duration: Duration(milliseconds: 2000))
      ..repeat();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller,
      builder: (context, child) {
        return CustomPaint(
          painter: WifiPainter(_controller.value, widget.color),
        );
      },
    );
  }
}

Painter

import 'dart:math';

import 'package:flutter/material.dart';

class WifiPainter extends CustomPainter {
  final double progress;
  final Color color;
  int count = 3;

  WifiPainter(this.progress, this.color);

  Paint _paint = Paint()
    ..style = PaintingStyle.stroke
    ..strokeWidth = 3
    ..strokeCap = StrokeCap.round;

  double angle = 0.35 * pi;

  @override
  void paint(Canvas canvas, Size size) {
    //0.05是一个余量,为了最后一个信号能显示
    final value = 1.0 / count - 0.05; 
    for (var i = 1; i <= count; i++) {
      //计算透明度
      final double opacity = progress >= i * value ? 1 : 0;
      final Color _color = color.withOpacity(opacity);
      _paint..color = _color;
      canvas.drawArc(
          Rect.fromCenter(
              center: size.center(Offset(0, size.height/2)),
              width: i * (size.width / count),
              height: i * (size.width / count)),
          (1.5 * pi) - angle / 2.0,
          angle,
          false,
          _paint);
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}