最近做了个项目需要有折线图和饼图 因为能查找到的资料很少 实现的过程比较艰难 所以记录下来。做的时候用到了 fl_chart 和 charts_flutter 两个库,今天先讲charts_flutter 。
charts_flutter的文档里面有丰富的示例图和示例代码。可以选择自己想要的样式的示例代码进行查看。
这次做的是饼图,就截一张饼图的示例图,每个点进去都有完整的示例代码。
打开项目下的pubspec.yaml
文件,在 dependencies
下添加 charts_flutter: ^0.9.0
(添加完别忘了flutter pub get,最新版请在charts_flutter上查看)
先拿到上图中第一个的示例代码,放到自己的项目中跑起来看看效果。
/// Simple pie chart example.
import 'package:charts_flutter/flutter.dart' as charts;
import 'package:flutter/material.dart';
class SimplePieChart extends StatelessWidget {
final List<charts.Series> seriesList;
final bool animate;
SimplePieChart(this.seriesList, {
this.animate});
/// Creates a [PieChart] with sample data and no transition.
factory SimplePieChart.withSampleData() {
return new SimplePieChart(
_createSampleData(),
// Disable animations for image tests.
animate: false,
);
}
@override
Widget build(BuildContext context) {
return new charts.PieChart(seriesList, animate: animate);
}
/// Create one series with sample hard coded data.
static List<charts.Series<LinearSales, int>> _createSampleData() {
final data = [
new LinearSales(0, 100),
new LinearSales(1, 75),
new LinearSales(2, 25),
new LinearSales(3, 5),
];
return [
new charts.Series<LinearSales, int>(
id: 'Sales',
domainFn: (LinearSales sales, _) => sales.year,
measureFn: (LinearSales sales, _) => sales.sales,
data: data,
)
];
}
}
/// Sample linear data type.
class LinearSales {
final int year;
final int sales;
LinearSales(this.year, this.sales);
}
@override
Widget build(BuildContext context) {
return new charts.PieChart(seriesList, animate: animate);
}
首先,创建饼图的方式为 new charts.PieChart();
,然后在括号里传入所需的参数。在AndroidStudio
中按住ctrl
,并将光标移到PieCHart
上可以看到具体的参数信息。示例代码中,传入了seriesList
和animate
。
1.seriesList: 既然是饼图,那就需要数据,根据不同数据的大小,来显示不同的占比。
这里的数据类型为List
,很明显这是库定义的类型,我们只要学会怎么去生成这种数据,就能放入饼图中使用。
首先是创建一个数据模型,可以根据自己的需求进行定义。示例代码中定义的LinearSales
有两个属性,分别为year
和sales
,顾名思义应该是不同年份的销量进行对比。
class LinearSales {
final int year;
final int sales;
LinearSales(this.year, this.sales);
}
创建完后,就可以生成数据了,下面是示例代码中的数据。
static List<charts.Series<LinearSales, int>> _createSampleData() {
final data = [
new LinearSales(0, 100),
new LinearSales(1, 75),
new LinearSales(2, 25),
new LinearSales(3, 5),
];
return [
new charts.Series<LinearSales, int>(
// 1.id:这里要求填入一个id,既然人家要求了那就设置一个以免出现问题吧。
id: 'Sales',
// 2.domianFn:这个属性相当于折线图或柱状图的横坐标
domainFn: (LinearSales sales, _) => sales.year,
// 3.measureFn:这个属性相当于折线图或柱状图的纵坐标,也就是比较的数值
measureFn: (LinearSales sales, _) => sales.sales,
// 4.data:这个就是要传入的自己的数据
data: data,
)
];
}
简单的说下return
里的内容: 遍历data
中的数据,先拿出第一个LinearSales(0, 100)
,然后domainFn
中的sales
即为LinearSales(0, 100)
,此时的sales.year
就是0
,measureFn
中也一样,此时的sales.sales
就是100
。之后以此类推拿出第二个第三个数据。
2.animate: bool类型。是true的时候,会有一个动画效果(生成时的动画)。效果如下:
很明显,我们平时项目要求的样式,和这个示例图有着不小的出入,我们该如何去根据自己的需求来进行修改。
在charts.PieChart
中,有个属性叫defaultRenderer
,根据名字可以认为这是一个默认渲染,当没有重写的时候,默认的就是上面示例图的样式,而我们可以根据自己的需求通过new charts.ArcRendererConfig()
的方式重写这个属性。
@override
Widget build(BuildContext context) {
return new charts.PieChart(
seriesList,
defaultRenderer: new charts.ArcRendererConfig(
arcWidth: int,
arcRendererDecorators: [],
... // 这里有挺多属性的 由于我项目中只用到了上面2个属性 所以没有深究其他的 有兴趣的可以自己看源码
)
);
}
1.arcWidth: 下图是arcWidth设置为40的样式,arcWidth的值即为圆环的宽度,值越小,宽度越小
2.arcRendererDecorators: 之前的图里都没有文字,看起来不直观,不知道哪部分是什么。通过这个属性,可以把内容显示出来。
先介绍一下部分属性,分别为labelPosition
,showLeaderLines
,leaderLineStyleSpec
,insideLabelStyleSpec
,outsideLabelStyleSpec
。剩余的可以看源码了解
labelPosition: 可以控制文字在饼图内部还是外部,设置成inside
时在里面,outside
时在外面,也可以设置成auto
,默认内部,当文字显示不下时会自动放在外面。当文字在内部的时候,跟LeaderLine
有关的内容就不生效,因为指引线是跟外面的文字所连接的。
showLeaderLines: 该属性用来控制文字在外面时显不显示指引线,默认是true即显示。
其他三个Spec结尾的属性: Spec结尾的均为设置样式,根据名字可以知道分别是内部文字样式,外部文字样式和指引线样式,可以根据下面代码查看编写方式,并不难。不过需要注意其中的Color
类需要用该库中的Color
类。需要通过charts.ColorUtil.fromDartColor(Colors.orange)
的方式在()
传入颜色值来设置颜色。
arcRendererDecorators: [
new charts.ArcLabelDecorator(
labelPosition: charts.ArcLabelPosition.outside,
showLeaderLines: true,
insideLabelStyleSpec: charts.TextStyleSpec(
color: charts.ColorUtil.fromDartColor(Colors.orange),
fontSize: 14),
outsideLabelStyleSpec: charts.TextStyleSpec(
color: charts.ColorUtil.fromDartColor(Colors.orange),
fontSize: 14),
leaderLineStyleSpec: charts.ArcLabelLeaderLineStyleSpec(
color: charts.ColorUtil.fromDartColor(Colors.orange),
length: 15.0,
thickness: 1.0
),
)
]
上面代码的效果如下:
现在为止,可以发现一个问题,刚才的样式设置,都是统一的,一设置,所有文字的颜色都会变。假如我们需要对不同的文字设置不同的颜色,同时将饼图中各部分的颜色设置成和文字相同,那么就需要在数据中设置。即示例代码中的seriesList
。因为涉及到颜色值,所以我们修改一下数据模型和数据。
首先是数据模型,这里将year
改成String
只是为了说明该类型不局限于int
class LinearSales {
String year;
int sales;
Color colorVal;
LinearSales(this.year, this.sales,this.colorVal);
}
下面是数据:
colorFn: 在这里传入sales.colorVal
就可以改变饼图各部分的颜色了。
outsideLabelStyleAccessorFn: 这里是外部文字样式,也可以传入sales.colorVal
来设置颜色
labelAccessorFn: 这个是显示的文字,通过自己的拼接显示出相应格式的文字。下面代码中的'${sales.year}: ${sales.sales}'
对应的第一个数据就是 2017:95
List<charts.Series<LinearSales, String>> _createSampleData() {
final data = [
new LinearSales('2017', 95, Colors.red),
new LinearSales('2018', 75, Colors.grey),
new LinearSales('2019', 25, Colors.green),
new LinearSales('2020', 5, Colors.blue),
];
return [
new charts.Series<LinearSales, String>(
id: 'Sales',
data: data,
domainFn: (LinearSales sales, _) => sales.year,
measureFn: (LinearSales sales, _) => sales.sales,
colorFn: (LinearSales sales, _) => charts.ColorUtil.fromDartColor(sales.colorVal),
labelAccessorFn: (LinearSales sales, _) => '${sales.year}:${sales.sales}',
outsideLabelStyleAccessorFn: (LinearSales sales, _) =>
charts.TextStyleSpec(
fontSize: 12,
color: charts.ColorUtil.fromDartColor(sales.colorVal),
)
)
];
}
下面是相应的界面:
问题: 指引线暂时没看到如何单独设置颜色,不知道有没有看漏什么。第一次花心思写博客,如果哪里有问题或者有什么意见和建议都可以提。
demo已上传