美文网首页
自定义柱状图

自定义柱状图

作者: 卢融霜 | 来源:发表于2023-08-06 17:41 被阅读0次

    自定义一个柱状图
    [图片上传失败...(image-9a235c-1691401253525)]

    import 'package:flutter/material.dart';
    
    import 'dotted_dashed_line.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
            useMaterial3: true,
          ),
          home: const MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({super.key, required this.title});
    
      final String title;
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      List<ListColumn> list = [
        ListColumn("周一", [
          ColumnItem(0, Colors.green),
          ColumnItem(0, Colors.red),
          ColumnItem(0, Colors.blue)
        ]),
        ListColumn("周二", [
          ColumnItem(0, Colors.green),
          ColumnItem(0, Colors.red),
          ColumnItem(0, Colors.blue)
        ]),
        ListColumn(
          "周三",
          [
            ColumnItem(0, Colors.green),
            ColumnItem(0, Colors.red),
            ColumnItem(0, Colors.blue)
          ],
        ),
        ListColumn(
          "周四",
          [
            ColumnItem(0, Colors.green),
            ColumnItem(0, Colors.red),
            ColumnItem(0, Colors.blue)
          ],
        ),
        ListColumn("周五", [
          ColumnItem(0, Colors.green),
          ColumnItem(0, Colors.red),
          ColumnItem(0, Colors.blue)
        ]),
        ListColumn(
          "周六",
          [
            ColumnItem(0, Colors.green),
            ColumnItem(0, Colors.red),
            ColumnItem(0, Colors.blue)
          ],
        ),
        ListColumn("周日", [
          ColumnItem(0, Colors.green),
          ColumnItem(0, Colors.red),
          ColumnItem(0, Colors.blue)
        ])
      ];
    
      @override
      void initState() {
        super.initState();
        Future.delayed(const Duration(seconds: 4), () {
          list = [
            ListColumn("周一", [
              ColumnItem(20, Colors.green),
              ColumnItem(10, Colors.red),
              ColumnItem(20, Colors.blue)
            ]),
            ListColumn("周二", [
              ColumnItem(50, Colors.green),
              ColumnItem(60, Colors.red),
              ColumnItem(20, Colors.blue)
            ]),
            ListColumn(
              "周三",
              [
                ColumnItem(40, Colors.green),
                ColumnItem(30, Colors.red),
                ColumnItem(10, Colors.blue)
              ],
            ),
            ListColumn(
              "周四",
              [
                ColumnItem(60, Colors.green),
                ColumnItem(10, Colors.red),
                ColumnItem(20, Colors.blue)
              ],
            ),
            ListColumn("周五", [
              ColumnItem(15, Colors.green),
              ColumnItem(15, Colors.red),
              ColumnItem(5, Colors.blue)
            ]),
            ListColumn(
              "周六",
              [
                ColumnItem(40, Colors.green),
                ColumnItem(12, Colors.red),
                ColumnItem(8, Colors.blue)
              ],
            ),
            ListColumn("周日", [
              ColumnItem(22, Colors.green),
              ColumnItem(13, Colors.red),
              ColumnItem(16, Colors.blue)
            ])
          ];
          setState(() {});
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                backgroundColor: Theme.of(context).colorScheme.inversePrimary,
                title: Text(widget.title)),
            body: HistogramWidget(height: 300, list: list));
      }
    }
    
    class HistogramWidget extends StatefulWidget {
      final double height;
      final List<ListColumn> list;
    
      const HistogramWidget({required this.height, required this.list, super.key});
    
      @override
      State<HistogramWidget> createState() => _HistogramWidgetState();
    }
    
    class _HistogramWidgetState extends State<HistogramWidget> {
      double px = 1;
    
      ///误差线
      List<int> lines = [];
    
      ///获取数组最大数
      double findMax(List<double> numbers) {
        if (numbers.isEmpty) {
          return 0;
        }
        double max = numbers[0];
        for (double number in numbers) {
          if (number > max) {
            max = number;
          }
        }
        return max;
      }
    
      ///获取误差线
      List<int> calculateNodes(double inputNumber) {
        var item = nearestMultipleOf5(nearestMultipleOf5(inputNumber ~/ 2) ~/ 2);
        return [0, item, item * 2, item * 3, item * 4];
      }
    
      ///获取就近 大于当前的5的倍数
      int nearestMultipleOf5(int number) {
        int nextMultiple = ((number ~/ 5) + 1) * 5;
        return nextMultiple;
      }
    
      @override
      Widget build(BuildContext context) {
        ///获取比例
        List<double> ints = [];
        for (var element in widget.list) {
          double total = 0;
          for (var element in element.list) {
            total += element.value;
          }
          ints.add(total);
        }
    
        ///获取最大数
        double max = findMax(ints);
        if (max == 0) {
          max = 100;
        }
    
        ///获取误差线
        lines = calculateNodes(max);
        px = widget.height / lines[lines.length - 1];
    
        return SizedBox(
            height: (widget.height + 40),
            child: Column(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.end,
                children: [
                  Expanded(child: Stack(fit: StackFit.expand, children: getLines()))
                ]));
      }
    
      getColumnChildren() {
        List<Widget> children = [];
        for (var element in widget.list) {
          children.add(ColumnWidget(listColumn: element, px: px));
        }
        return children;
      }
    
      List<Widget> getLines() {
        List<Widget> lis = [];
        for (var element in lines) {
          lis.add(Positioned(
              bottom: element * px,
              left: 0,
              right: 0,
              child: XLine(title: "$element")));
        }
        lis.add(Align(
            alignment: Alignment.bottomCenter,
            child: AnimatedContainer(
                padding: const EdgeInsets.only(left: 30, right: 10),
                duration: const Duration(seconds: 1),
                child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    crossAxisAlignment: CrossAxisAlignment.end,
                    children: getColumnChildren()))));
    
        return lis;
      }
    }
    
    class ColumnWidget extends StatelessWidget {
      final ListColumn listColumn;
      final double px;
    
      const ColumnWidget({required this.listColumn, required this.px, super.key});
    
      @override
      Widget build(BuildContext context) {
        return Transform.translate(
          offset: const Offset(0, 20),
          child: Column(
            children: [
              Expanded(
                  child: Align(
                      alignment: Alignment.bottomCenter,
                      child: Column(
                        mainAxisSize: MainAxisSize.min,
                        children: getChildren(listColumn.list),
                      ))),
              SizedBox(
                  height: 20,
                  child: Center(
                      child: Text(listColumn.title,
                          style: const TextStyle(color: Colors.red))))
            ],
          ),
        );
      }
    
      List<Widget> getChildren(List<ColumnItem> listValue) {
        List<Widget> children = [];
        for (int i = 0; i < listValue.length; i++) {
          children.add(AnimatedContainer(
            width: 21,
            height: listValue[i].value * px,
            decoration: BoxDecoration(
                borderRadius: i == 0
                    ? const BorderRadius.only(
                        topLeft: Radius.circular(3), topRight: Radius.circular(3))
                    : null,
                color: listValue[i].color),
            duration: const Duration(seconds: 1),
          ));
        }
        return children;
      }
    }
    
    class ListColumn {
      final String title;
      final List<ColumnItem> list;
    
      const ListColumn(this.title, this.list);
    }
    
    class ColumnItem {
      final double value;
      final Color color;
    
      ColumnItem(this.value, this.color);
    }
    
    class XLine extends StatelessWidget {
      final String title;
    
      const XLine({required this.title, super.key});
    
      @override
      Widget build(BuildContext context) {
        return Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(title),
            const DottedDashedLine(
                height: 1, width: double.infinity, axis: Axis.horizontal)
          ],
        );
      }
    }

    相关文章

      网友评论

          本文标题:自定义柱状图

          本文链接:https://www.haomeiwen.com/subject/hwrwpdtx.html