优美的应用体验 来自于细节的处理,更源自于码农的自我要求与努力,当然也需要码农年轻灵活的思维,不局限于思维,不局限语言限制,才是编程的最高境界。

很多人会谈论到程序员35岁的问题,在我看来,无论是程序员还是各行各业中,真正限制人的不是年龄,是一颗持续学习的心,在码农的世界里,优美的应用体验,来源于程序员对细节的处理以及自我要求的境界,年轻人也是忙忙碌碌的码农中一员,每天、每周,都会留下一些脚印,就是这些创作的内容,有一种执着,就是不知为什么,如果你迷茫,不妨来瞅瞅码农的轨迹。

本文章实现的效果如下图所示:

Flutter 动态饼状图 让你的APP中无聊的统计图动起来 挻舒适的感觉瞬间提升一个档次 -深夜创作_Flutter学习

1 单文件测试

在 Flutter 项目中随便创建一个 dart 文件,然后就可以做为一个应用启动,只需要

//定义一个全局的内容主颜色
Color mainColor = Color(0xFFCADCED);

///程序入口
void main() {
//启动根目录
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
home: TestPieAnimationPage(),
),
);
}

然后默认的首页面就是一个 StatefulWidget,代码如下:

///默认显示的首页面
class TestPieAnimationPage extends StatefulWidget {
@override
_TestPieAnimationPageState createState() => _TestPieAnimationPageState();
}


class _TestPieAnimationPageState extends State<TestPieAnimationPage>
with SingleTickerProviderStateMixin {
... ...
}

首先初始化一些动画操作


//来个动画控制器
AnimationController _animationController;

//控制背景抬高使用的
Animation<double> _bgAnimation;

//控制饼图使用的
Animation<double> _progressAnimation;

//控制数字使用的
Animation<double> _numberAnimation;

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

//初始化一下
_animationController = new AnimationController(
//执行时间为 1 秒
duration: Duration(milliseconds: 1000),
vsync: this);

//在 0~500毫秒内 执行背景阴影抬高的操作
_bgAnimation = Tween(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: _animationController,
//执行时间 区间
curve: Interval(0.0, 0.5,curve: Curves.bounceOut),
),
);

//在 400 ~ 800 毫秒的区间内执行画饼的操作动画
_progressAnimation = Tween(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: _animationController,
//执行时间 区间
curve: Interval(0.4, 0.8,curve: Curves.bounceOut),
),
);

//在 700 ~ 1000 毫秒的区间 执行最上层的数字抬高的操作动画
_numberAnimation = Tween(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: _animationController,
//执行时间 区间
curve: Interval(0.7, 1.0,curve: Curves.bounceOut),
),
);

//添加 一个监听 刷新页面
_animationController.addListener(() {
setState(() {
});
});
}

Curves.bounceOut 是动画曲线 如下图所示

Flutter 动态饼状图 让你的APP中无聊的统计图动起来 挻舒适的感觉瞬间提升一个档次 -深夜创作_Flutter学习_02

2 build 方法页面主视图构建

Flutter 动态饼状图 让你的APP中无聊的统计图动起来 挻舒适的感觉瞬间提升一个档次 -深夜创作_Flutter学习_03

  @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();
},
),
);
}

2.1 通过Row左右排列 图例与饼图

  buildRow() {
//左右排列的线性布局
return Row(
children: [
//权重适配 占用宽度 5:6
Expanded(
flex: 5,
//左边是一个竖直方向排列的线性布局
child: buildLeftColumn(),
),
//右边就是饼图区域
Expanded(
flex: 6,
//层叠布局
child: buildRightStack(),
),
],
);
}

Flutter 动态饼状图 让你的APP中无聊的统计图动起来 挻舒适的感觉瞬间提升一个档次 -深夜创作_Flutter教程_04

2.2 左侧的图例

通过 Column 来竖直方向线性排列每一个图例条目,然后每一个图例条目再使用Row来水平排开小图标与文字,代码如下:


//定义数据模型
List _list = [
{"title": "生活费", "number": 200, "color": Colors.lightBlueAccent},
{"title": "交通费", "number": 200, "color": Colors.green},
{"title": "贷款费", "number": 400, "color": Colors.amber},
{"title": "游玩费", "number": 100, "color": Colors.orange},
{"title": "电话费", "number": 100, "color": Colors.deepOrangeAccent},
];

//左边
Column buildLeftColumn() {
return Column(
//设置包裹子Widget
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),
decoration: BoxDecoration(
color: data["color"],
shape: BoxShape.circle,
),
width: 10,
height: 10,
),
Text(
data["title"],
style: TextStyle(fontSize: 16),
),
],
),
);
},
).toList(),
);
}

Flutter 动态饼状图 让你的APP中无聊的统计图动起来 挻舒适的感觉瞬间提升一个档次 -深夜创作_Flutter学习_05

2.3 右侧的饼图

是通过 Stack 层叠布局将两个Container容器层叠在一起,阴影效果是通过 BoxDecoration 的 BoxShadow 来实现,代码如下:

  Stack buildRightStack() {
return Stack(
//子 Widget 居中
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: CustomShapPainter(_list, _progressAnimation.value),
),
),
//第二层
Container(
width: 100,
decoration: BoxDecoration(
color: mainColor,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
spreadRadius: 3 * _numberAnimation.value,
blurRadius: 5 * _numberAnimation.value,
offset: Offset(
5 * _numberAnimation.value, 5 * _numberAnimation.value),
color: Colors.black54),
],
),
child: Center(
child: Text(
"¥100",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 22),
),
),
),
],
);
}

Flutter 动态饼状图 让你的APP中无聊的统计图动起来 挻舒适的感觉瞬间提升一个档次 -深夜创作_Flutter教程_06

2.4 绘制饼图

就是在自定义的 CustomPainter 中搞定的,代码如下:

class CustomShapPainter extends CustomPainter {
//数据内容
List list;

double progress;

CustomShapPainter(this.list, this.progress);

//来个画笔
Paint _paint = new Paint()..isAntiAlias = true;

//圆周率(Pi)是圆的周长与直径的比值,一般用希腊字母π表示
//绘制内容
@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 startRadian = -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),
startRadian, sweepRadin, true, _paint);

//累加下次开始绘制的角度
startRadian += sweepRadin;
}
}

//返回true 刷新
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}

Flutter 动态饼状图 让你的APP中无聊的统计图动起来 挻舒适的感觉瞬间提升一个档次 -深夜创作_Flutter教程_07

【x1】微信公众号的每日提醒 随时随记 每日积累 随心而过 文章底部扫码关注

​【x2】各种系列的视频教程 免费开源 关注 你不会迷路​

​【x3】系列文章 百万 Demo 随时 复制粘贴 使用​

​【x4】简短的视频不一样的体验​

​【x5】必须有源码​


不局限于思维,不局限语言限制,才是编程的最高境界。

以小编的性格,肯定是要录制一套视频的,随后会上传

有兴趣 你可以关注一下 ​​西瓜视频 — 早起的年轻人​

Flutter 动态饼状图 让你的APP中无聊的统计图动起来 挻舒适的感觉瞬间提升一个档次 -深夜创作_Flutter学习_08