应用程序中的图表提供了数据的图形显示或图画表示,跨越了行业和应用程序。像Mint这样的移动应用程序使用饼状图来监测消费习惯,像Strava这样的健身应用程序使用线状图和条状图来分析步幅、心率和海拔高度。
在构建Flutter应用程序时,开发者可以使用由谷歌维护的官方charts_flutter
库来创建这些类型的图表。
在本教程中,我们将学习如何使用charts_flutter
创建一些最常见的图表--线形图、饼图和条形图。
我们将用这些图表来显示一个虚构的Flutter图表开发者社区五年来的增长情况。虽然本教程中的数据是捏造的,但本教程可以很容易地利用真实数据。
要学习本教程,您必须具备以下条件。
charts_flutter
要创建一个新的Flutter项目,运行以下命令。
flutter create projectName
接下来,在您的代码编辑器中打开这个新项目。如上所述,我们将使用[chart_flutter](https://pub.dev/packages/charts_flutter)
,Flutter的官方库。
要将chart_flutter
导入您的项目,请打开pubspec.yaml
文件并将其添加到依赖项下。
dependencies:
flutter:
sdk: flutter
charts_flutter: ^0.11.0
现在我们有了新的Flutter应用程序所附带的基本代码:一个记录按钮被按下多少次的计数器。
由于我们的条形图应用程序中不需要这个,继续删除在main.dart
页面中发现的代码。删除所有的内容,除了下面的内容。
import ‘package:flutter/material.dart’;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
//TODO: implement build
Return MaterialApp(
);
}
}
现在,在我们的构建部件中返回MaterialApp
类,以便我们可以使用Material Design。
要为我们的应用程序创建一个主页,请导航到lib
文件夹,并创建一个名为home.dart
的新页面。
import 'package:flutter/material.dart';
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ,
),
);
}
}
通过import 'package:flutter/material.dart'
,我们就可以导入Material Design。
然后,HomePage
类扩展了statelessWidget
,因为在这个页面上没有状态变化。
在BuildContext
widget里面,我们返回Scaffold
类,给我们一个基本的Material Design布局结构。我们的条形图将放在子参数的位置,我们将把它放在屏幕主体的中心。
所有这些现在都成为我们应用程序的支架。
随着主页的完成,我们可以在我们的main.dart
文件中指定HomePage
,因为main.dart
将我们应用程序中的所有功能集中在一起。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(), //This is where we specify our homepage
);
}
}
有了这段代码,main.dart
就知道每当应用加载时首先显示哪一页。
请注意,将debugShowCheckedModeBanner
设置为false
,就可以从我们的应用程序中删除调试标记。
在我们创建图表应用之前,让我们熟悉一下Flutter图表常用的两个术语:系列和模型。
系列是一组(或系列)的信息,我们可以用它来绘制我们的图表。一个模型是我们的信息的格式,它规定了使用该模型的每个数据项必须具有的属性。
首先,我们将创建一个柱状图,以显示在过去五年中新增的虚构Flutter图表开发者的数量。换句话说,我们要跟踪虚构的Flutter图表社区的增长情况。
我们的模型,定义了我们的数据格式,包括我们要看的年份,那一年加入Flutter图表社区的开发者数量,以及相应条形图的颜色。
在lib
文件夹中,创建一个名为developer_series.dart
的文件。下面,实现我们模型的代码。
import 'package:charts_flutter/flutter.dart' as charts;
import 'package:flutter/foundation.dart';
class DeveloperSeries {
final int year;
final int developers;
final charts.Color barColor;
DeveloperSeries(
{
@required this.year,
@required this.developers,
@required this.barColor
}
);
}
我们将模型命名为DeveloperSeries
,并指定了每个系列项目必须具备的属性(year
,developers
, 和barColor
)。
为了防止在创建一个类的对象时,该类的参数为空,我们使用了@required
注释,如上面的代码块中所示。
要使用@required
关键字,我们必须导入foundation.dart
包。
现在我们有了一个条形图数据的模型,让我们继续实际创建一些数据。在主页上,通过添加以下内容为柱状图生成数据。
import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart' as charts;
import 'package:;lib/developer_series.dart';
class HomePage extends StatelessWidget {
final List data = [
DeveloperSeries(
year: "2017",
developers: 40000,
barColor: charts.ColorUtil.fromDartColor(Colors.green),
),
DeveloperSeries(
year: "2018",
developers: 5000,
barColor: charts.ColorUtil.fromDartColor(Colors.green),
),
DeveloperSeries(
year: "2019",
developers: 40000,
barColor: charts.ColorUtil.fromDartColor(Colors.green),
),
DeveloperSeries(
year: "2020",
developers: 35000,
barColor: charts.ColorUtil.fromDartColor(Colors.green),
),
DeveloperSeries(
year: "2021",
developers: 45000,
barColor: charts.ColorUtil.fromDartColor(Colors.green),
),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ,
),
);
}
}
这是一个名为data
的简单列表。列表中的每一个项目都是按照DeveloperSeries
的模型制作的,也就是说每一个项目都有一个年份(year
)、开发者的数量(developers
)和条形图的颜色(barColor
)的属性。
请注意,上面的数据是真实的,所以请随意操作这些数字和颜色。
我们已经成功地为我们的柱状图创建了数据。现在,让我们来创建条形图本身。为了使我们的项目有条理,我们将把柱状图的代码放在一个单独的文件中。
在lib
,创建一个developer_chart.dart
文件。
import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart' as charts;
import 'package:lib/developer_series.dart';
class DeveloperChart extends StatelessWidget {
final List data;
DeveloperChart({@required this.data});
@override
Widget build(BuildContext context) {
List> series = [
charts.Series(
id: "developers",
data: data,
domainFn: (DeveloperSeries series, _) => series.year,
measureFn: (DeveloperSeries series, _) => series.developers,
colorFn: (DeveloperSeries series, _) => series.barColor
)
];
Return charts.Barchart(series, animate: true);
}
}
通过final List
,我们定义了一个名为data
的列表,它是我们之前创建的DeveloperSeries
模型形式的数据项的List
。
列表中的每一个数据项都带有相应的年份、开发人员的数量和条形颜色。
类中的DeveloperChart
构造函数确保在使用条形图类的任何地方,它所需要的数据总是被提供;这是用@required
关键字完成的。
实际的柱状图是在我们的构建部件中创建的。如你所知,所有的柱状图都有几组数据相互对照(在我们的例子中,过去五年和Flutter图表社区获得的开发者数量)。
这些数据组在一起,被称为系列。系列告诉我们Flutter要把哪一组数据放在我们条形图的水平面,哪一组放在垂直面。
然后,我们先前创建的数据列表插入到我们的系列中,并由Flutter适当地使用。
通过List
,我们创建了一个名为series
的列表。这个列表的类型为charts.Series
;charts
将Flutter导入我们的项目,Series
函数为Flutter中的柱状图创建系列。
我们刚刚创建的系列是以我们的DeveloperSeries
模型为模型。
我们将在系列中指定的参数包括:id
,data
,domainFn
,measureFn
, 和colorFN
。
id
标识了图表data
指向要在柱状图上绘制的项目列表domainFn
指向柱状图水平方向上的数值。measureFn
指向垂直方向上的数值的数量colorFN
指的是条形图的颜色通过domainFn
,measureFn
, 和colorFN
函数,我们创建了以Subscriber
系列为参数的函数,创建了它的实例,然后使用这些实例来访问它的不同属性。
developer_chart.dart
文件中的下划线标志着第二个参数是不需要的。
在将我们的系列指向它所需要的所有数据后,我们再使用Flutter的BarChart
函数来创建我们的柱状图。
我们还可以通过简单地将animate
设置为true
来添加一个动画,以获得视觉上的吸引力,这将使图表呈现出一个漂亮的动画。
现在,我们可以将新创建的柱状图添加到我们的主页上并显示。
import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart' as charts;
import 'package:lib/developer_series.dart';
import 'package:lib/developer_chart.dart';
class HomePage extends StatelessWidget {
// ...
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: DeveloperChart(
data: data,
)
),
);
}
}
在这里,我们只需在我们的页面主体内调用DeveloperChart
类,并将其指向我们要使用的数据。
为了确保我们的图表能够很好地在屏幕上显示,我们将把它放在一个Card
,在它周围包裹一个容器,并给它设置一个高度和一些填充。
…
class DeveloperChart extends StatelessWidget {
final List data;
DeveloperChart({@required this.data});
@override
Widget build(BuildContext context) {
List> series = [
charts.Series(
id: "developers",
data: data,
domainFn: (DeveloperSeries series, _) => series.year,
measureFn: (DeveloperSeries series, _) => series.developers,
colorFn: (DeveloperSeries series, _) => series.barColor
)
];
return Container(
height: 300,
padding: EdgeInsets.all(25),
child: Card(
child: Padding(
padding: const EdgeInsets.all(9.0),
child: Column(
children: [
Text(
"Yearly Growth in the Flutter Community",
style: Theme.of(context).textTheme.body2,
),
Expanded(
child: charts.BarChart(series, animate: true),
)
],
),
),
),
);
}
}
通过使用expanded
widget,我们将我们的柱状图很好地扩展到Card
。上面的Text
widget给了我们的柱状图一个标题,让人们知道它是关于什么的。
而且,通过Theme.of(context).textTheme.body2
,我们将Material Design默认的正文样式应用于我们的标题。
通过padding: const EdgeInsets.all(9.0)
,我们给容纳我们的条形图的卡片在所有边上加了9px的填充。最后,我们将Card
包裹在一个容器中,并给这个容器一个300px的高度和25px的边距。
现在,我们的条形图应该能很好地呈现在我们的屏幕上。
我们也可以使用charts_flutter
包来创建饼图。事实上,我们上面遵循的程序和我们编写的代码可以创建饼图。
要将我们创建的条形图改为饼图,只需将charts.BarChart(series, animate: true)
改为child:( charts.PieChart(series, animate: true)
。
然后我们就可以在饼图上添加标签。
Expanded(
child: charts.PieChart(series,
defaultRenderer: charts.ArcRendererConfig(
arcRendererDecorators: [
charts.ArcLabelDecorator(
labelPosition: charts.ArcLabelPosition.inside)
])
animate: true),
)
ArcRendererConfig
函数可以配置饼图的外观,我们可以使用ArcLabelDecorator
函数为饼图添加标签。
labelPosition
指定将标签放在哪里,是放在里面还是外面;在这种情况下,我们指定标签应该放在外面。
我们可以用创建其他两个图表的同样方法来创建一个折线图。我们只需对我们的数据配置做一个小小的调整。
在我们的系列列表中,List
变成List
,因为折线图只对数字起作用。
List> series = [
charts.Series(
id: "developers",
data: data,
domainFn: (DeveloperSeries series, _) => series.year,
measureFn: (DeveloperSeries series, _) => series.developers,
colorFn: (DeveloperSeries series, _) => series.barColor
)
];
现在我们可以把charts.PieChart
改为charts.Linechart
,从而得到我们的折线图。默认情况下,折线图是从原点零开始的。但是我们所关注的年份是从2016年到2021年。因此,这里是如何使我们的折线图跨越这个范围的。
Expanded(
child: charts.LineChart(series,
domainAxis: const charts.NumericAxisSpec(
tickProviderSpec:
charts.BasicNumericTickProviderSpec(zeroBound: false),
viewport: charts.NumericExtents(2016.0, 2022.0),
),
animate: true),
)
NumericAxisSpec
函数为图表中的轴设置规格。通过BasicNumericTickProviderSpec
函数,我们将zeroBound
设置为false
,这样我们的图表就不会从原点零开始。
最后,通过NumericExtents
函数,我们设置了我们希望我们的坐标轴所跨越的范围。
本教程的目的是向Flutter开发者展示如何在其应用程序中实现不同的图表。使用谷歌创建的强大的charts_flutter
包,我们能够实现一个柱状图、一个饼状图和一个线形图。
要了解这个包的更多功能,请到pub.dev上查看。