返回

弹指一挥间,Flutter自组蛛网图绘制+动画实践

Android

1. 静态蛛网图

1.1 创建AbilityWidget组件

在 Flutter 中,自定义组件是构建复杂界面的基石。为了创建蛛网图,我们需要一个名为AbilityWidget的自定义组件。这个组件将负责绘制蛛网图的各个元素,如外圈、内圈和文字。

class AbilityWidget extends StatelessWidget {
  final double value;
  final String name;

  const AbilityWidget({Key key, @required this.value, @required this.name}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: AbilityPainter(value: value, name: name),
    );
  }
}

1.2 绘制外圈

外圈是蛛网图的核心元素,它代表了整体数据范围。在AbilityPainter类中,我们使用drawCircle方法绘制外圈。

class AbilityPainter extends CustomPainter {
  final double value;
  final String name;

  AbilityPainter({@required this.value, @required this.name});

  @override
  void paint(Canvas canvas, Size size) {
    // 绘制外圈
    final outerCirclePaint = Paint()
      ..color = Colors.grey[200]
      ..strokeWidth = 2.0;
    canvas.drawCircle(size.center(Offset.zero), size.width / 2, outerCirclePaint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

1.3 绘制内圈

内圈是蛛网图的第二层元素,它代表了数据的分段范围。在AbilityPainter类中,我们使用drawArc方法绘制内圈。

class AbilityPainter extends CustomPainter {
  final double value;
  final String name;

  AbilityPainter({@required this.value, @required this.name});

  @override
  void paint(Canvas canvas, Size size) {
    // 绘制内圈
    final innerCirclePaint = Paint()
      ..color = Colors.blue[400]
      ..strokeWidth = 2.0;
    final rect = Rect.fromCircle(center: size.center(Offset.zero), radius: size.width / 2);
    canvas.drawArc(rect, -pi / 2, value * pi, false, innerCirclePaint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

1.3 绘制文字

文字是蛛网图的重要组成部分,它标识了每个数据段的名称和值。在AbilityPainter类中,我们使用drawText方法绘制文字。

class AbilityPainter extends CustomPainter {
  final double value;
  final String name;

  AbilityPainter({@required this.value, @required this.name});

  @override
  void paint(Canvas canvas, Size size) {
    // 绘制文字
    final textStyle = TextStyle(fontSize: 12.0, color: Colors.black);
    final textPainter = TextPainter(
      text: TextSpan(text: '$name: ${(value * 100).toStringAsFixed(1)}%', style: textStyle),
      textDirection: TextDirection.ltr,
    );
    textPainter.layout();
    textPainter.paint(canvas, size.center(Offset.zero) + Offset(0.0, -size.height / 4));
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

1.4 绘制范围

范围是蛛网图的外围元素,它指示了数据段的最高值和最低值。在AbilityPainter类中,我们使用drawRange方法绘制范围。

class AbilityPainter extends CustomPainter {
  final double value;
  final String name;

  AbilityPainter({@required this.value, @required this.name});

  @override
  void paint(Canvas canvas, Size size) {
    // 绘制范围
    final rangePaint = Paint()
      ..color = Colors.grey[200]
      ..strokeWidth = 1.0;
    canvas.drawLine(Offset(size.width / 2, 0.0), Offset(size.width / 2, size.height), rangePaint);
    canvas.drawLine(0.0, size.height / 2, size.width, size.height / 2, rangePaint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

2. 动画效果

为了让蛛网图更加生动,我们添加了动画效果。在AbilityWidget类中,我们使用TweenAnimationBuilder来实现动画效果。

class AbilityWidget extends StatefulWidget {
  final double value;
  final String name;

  const AbilityWidget({Key key, @required this.value, @required this.name}) : super(key: key);

  @override
  _AbilityWidgetState createState() => _AbilityWidgetState();
}

class _AbilityWidgetState extends State<AbilityWidget> with SingleTickerProviderStateMixin {
  Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    _animation = Tween(begin: 0.0, end: widget.value).animate(CurvedAnimation(parent: _controller, curve: Curves.easeIn));
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: AbilityPainter(value: _animation.value, name: widget.name),
    );
  }

  final AnimationController _controller = AnimationController(vsync: this, duration: Duration(seconds: 1));

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

3. 组件封装

现在,我们已经创建了AbilityWidget组件,并添加了动画效果。我们可以将这个组件封装成一个单独的Dart包,这样其他开发者就可以轻松地将其集成到他们的项目中。

结语

在这个教程中,我们学习了如何使用Flutter构建一个动态的蛛网图组件,包括绘制外圈、内圈、文字和范围,以及添加动画效果。希望这个教程对你有帮助,也欢迎你提出问题或建议。