flutter:纯手工绘制饼图

好累,不用插件真的是费神啊

本博主用flutter纯手工打造饼图,canvas绘制,好累,记得收藏学习哦,我的小粉丝们~

老规矩,看效果
在这里插入图片描述
上代码:

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


void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: piepage(),
    );
  }
}

class piepage extends StatefulWidget {
  @override
  _piepageState createState() => _piepageState();
}

Color mainColor = Color(0xFFCADCED);

class _piepageState extends State<piepage> with SingleTickerProviderStateMixin {
  AnimationController _animationController;

  Animation<double> _bgAnimation;

  Animation<double> _progressAnimation;

  Animation<double> _numberAnimation;

  @override
  void initState() {
    super.initState();

    _animationController = new AnimationController(
        duration: Duration(milliseconds: 1000), vsync: this);

    _bgAnimation = Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(
      parent: _animationController,
      curve: Interval(0.0, 0.5),
    ));

    _progressAnimation = Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(
      parent: _animationController,
      curve: Interval(0.4, 0.8),
    ));

    _numberAnimation = Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(
      parent: _animationController,
      curve: Interval(0.7, 1.0),
    ));

    _animationController.addListener(() {
      setState(() {});
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Container(
          height: 260,
          width: MediaQuery.of(context).size.width,
          //背景
          color: mainColor,
          //封装方法
          child: buildRow(),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          _animationController.reset();
          _animationController.forward();
        },
      ),
    );
  }

  //定义数据模型
  List _list = [
    {"title": "生活费", "number": 200, "color": Colors.lightBlueAccent},
    {"title": "伙食费", "number": 200, "color": Colors.deepOrangeAccent},
    {"title": "交通费", "number": 400, "color": Colors.green},
    {"title": "网购", "number": 300, "color": Colors.red},
    {"title": "电话费", "number": 200, "color": Colors.orange}
  ];

  buildRow() {
    return Row(
      children: [
        Expanded(
          flex: 5,
          child: buildLeftColumn(), //左边
        ),
        //饼图区域
        Expanded(
            flex: 6,
            child: Stack(
              alignment: Alignment.center,
              children: [
                //第一层
                Container(
                  padding: EdgeInsets.all(22),
                  decoration: BoxDecoration(
                      color: mainColor,
                      shape: BoxShape.circle,
                      boxShadow: [
                        BoxShadow(
                          color: Colors.white,
                          spreadRadius: -8 * _bgAnimation.value,
                          offset: Offset(
                              -5 * _bgAnimation.value, -5 * _bgAnimation.value),
                          //阴影偏移量
                          blurRadius: 30 * _bgAnimation.value,
                        ),
                        BoxShadow(
                          color: Colors.blue[300].withOpacity(0.3),
                          spreadRadius: 2 * _bgAnimation.value,
                          offset: Offset(
                              5 * _bgAnimation.value, 5 * _bgAnimation.value),
                          //阴影偏移量
                          blurRadius: 20 * _bgAnimation.value,
                        )
                      ]),

                  //开始绘制
                  child: CustomPaint(
                    size: Size(200, 200),
                    painter:
                        CustomShapePainter(_list, _progressAnimation.value),
                  ),
                ),
              ],
            ))
      ],
    );
  }

//左边
  Column buildLeftColumn() {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: _list.map(
        (data) {
          return Container(
              padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
              child: Row(
                children: [
                  Container(
                    margin: EdgeInsets.only(right: 10),
                    width: 10,
                    height: 10,
                    decoration: BoxDecoration(
                      color: data['color'],
                      shape: BoxShape.circle,
                    ),
                  ),
                  Text(
                    data['title'],
                    style: TextStyle(fontSize: 16),
                  )
                ],
              ));
        },
      ).toList(),
    );
  }
}

class CustomShapePainter extends CustomPainter {
  List list;

  double progress;

  CustomShapePainter(this.list, this.progress);

  Paint _paint = new Paint()..isAntiAlias = true;

  @override
  void paint(Canvas canvas, Size size) {
//中心
    Offset center = Offset(size.width / 2, size.height / 2);
    //半径
    double radius = min(size.width / 2, size.height / 2);
    //弧度
    double starRadian = -pi / 2;

    double total = 0.0;

    list.forEach((element) {
      total += element['number'];
    });

    for (var i = 0; i < list.length; i++) {
      var item = list[i];
      double flag = item['number'] / total;

      double sweepRadin = flag * 2 * pi * progress;

      _paint.color = item['color'];

      canvas.drawArc(Rect.fromCircle(center: center, radius: radius),
          starRadian, sweepRadin, true, _paint);

      starRadian += sweepRadin;
    }
  }

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

猜你喜欢

转载自blog.csdn.net/weixin_45425105/article/details/114094493
今日推荐