Flutter自定义系列之折线波动图,心率图,价格走势图

随着前两篇文章的学习,我今天继续给大家演示下简单的自定义之折线波动图,心率图,价格走势图。

这里,我们创建一个自定义的StatefulWidget,用于显示动态的价格线。

我们将使用CustomPaint和CustomPainter来绘制价格线。

lib/main.dart文件中添加以下代码:

import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('动态价格线')),
        body: DynamicPriceLine(),
      ),
    );
  }
}

class DynamicPriceLine extends StatefulWidget {
  @override
  _DynamicPriceLineState createState() => _DynamicPriceLineState();
}

class _DynamicPriceLineState extends State {
  List prices = List.generate(100, (index) => 50);
  Timer _timer;

  @override
  void initState() {
    super.initState();
    _timer = Timer.periodic(Duration(milliseconds: 100), (timer) {
      setState(() {
        prices.removeAt(0);
        double lastPrice = prices.last;
        double newPrice = lastPrice + (Random().nextDouble() * 4 - 2);
        prices.add(newPrice);
      });
    });
  }

  @override
  void dispose() {
    _timer.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: LinePainter(prices),
    );
  }
}

class LinePainter extends CustomPainter {
  final List prices;

  LinePainter(this.prices);

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.blue
      ..strokeWidth = 2
      ..style = PaintingStyle.stroke;

    final double minY = prices.reduce(min);
    final double maxY = prices.reduce(max);
    final double rangeY = maxY - minY;

    final double scaleX = size.width / (prices.length - 1);
    final double scaleY = size.height / rangeY;

    for (int i = 1; i < prices.length; i++) {
      canvas.drawLine(
        Offset((i - 1) * scaleX, size.height - (prices[i - 1] - minY) * scaleY),
        Offset(i * scaleX, size.height - (prices[i] - minY) * scaleY),
        paint,
      );
    }
  }

  @override
  bool shouldRepaint(covariant LinePainter oldDelegate) =>
      oldDelegate.prices != prices;
}

现在,运行你的应用程序,你将看到一个类似心率图的动态价格线。

发现价格线不动,界面没有实时展示。

运行发现并不能满足我们的需求,我们要一个整个视图要自动向左边移动,始终展示最新的绘制线。

思考之后我决定将使用Transform.translate来实现视图的移动效果


class DynamicPriceLine extends StatefulWidget {
  @override
  _DynamicPriceLineState createState() => _DynamicPriceLineState();
}

class _DynamicPriceLineState extends State {
  List prices = List.generate(100, (index) => 50);
  Timer _timer;
  double offsetX = 0;

  @override
  void initState() {
    super.initState();
    _timer = Timer.periodic(Duration(milliseconds: 100), (timer) {
      setState(() {
        offsetX -= 2;
        prices.removeAt(0);
        double lastPrice = prices.last;
        double newPrice = lastPrice + (Random().nextDouble() * 4 - 2);
        prices.add(newPrice);
      });
    });
  }

  @override
  void dispose() {
    _timer.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Transform.translate(
      offset: Offset(offsetX, 0),
      child: CustomPaint(
        painter: LinePainter(prices),
      ),
    );
  }
}

class LinePainter extends CustomPainter {
  final List prices;

  LinePainter(this.prices);

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.blue
      ..strokeWidth = 2
      ..style = PaintingStyle.stroke;

    final double minY = prices.reduce(min);
    final double maxY = prices.reduce(max);
    final double rangeY = maxY - minY;

    final double scaleX = size.width / (prices.length - 1);
    final double scaleY = size.height / rangeY;

    for (int i = 1; i < prices.length; i++) {
      canvas.drawLine(
        Offset((i - 1) * scaleX, size.height - (prices[i - 1] - minY) * scaleY),
        Offset(i * scaleX, size.height - (prices[i] - minY) * scaleY),
        paint,
      );
    }
  }

  @override
  bool shouldRepaint(covariant LinePainter oldDelegate) =>
      oldDelegate.prices != prices;
}

我们使用了Transform.translate来实现视图的移动效果。

每次更新价格数据时,offsetX将减去一个固定值(例如2),从而使视图向左移动。

现在运行你的应用程序,你将看到一个动态价格线,并且视图会自动向左移动以始终显示最新的绘制线。

Flutter自定义系列之折线波动图,心率图,价格走势图_第1张图片

上图就是基本的自定义显示效果,没有录屏,原谅我,如果是动态的更直观。

当然这都是最基本的自定义,需要扩展的大家下来实现吧。

你可能感兴趣的:(flutter,android)