Flutter - 对带有模型的图表使用 API
Posted
技术标签:
【中文标题】Flutter - 对带有模型的图表使用 API【英文标题】:Flutter - Using API for charts with model 【发布时间】:2021-05-18 21:21:53 【问题描述】:我被这个问题困扰了将近 3 天。已经将其发布在另一个问题中,但是得到了减号而不是答案。 让我把问题说清楚。 我想将使用模型的 api 数据放入图表颤动中,这是我的代码 首先是我的模型这里是我的年龄模型
ages.dart
Ages agesFromJson(String str) => Ages.fromJson(json.decode(str));
String agesToJson(Ages data) => json.encode(data.toJson());
class Ages
Ages(
this.entity,
this.code,
this.year,
this.underAge15,
this.age1564,
this.age65Over,
);
String entity;
String code;
int year;
String underAge15;
String age1564;
String age65Over;
factory Ages.fromJson(Map<String, dynamic> json) => Ages(
entity: json["entity"],
code: json["code"],
year: json["year"],
underAge15: json["under_age_15"],
age1564: json["age_15_64"],
age65Over: json["age_65_over"],
);
Map<String, dynamic> toJson() =>
"entity": entity,
"code": code,
"year": year,
"under_age_15": underAge15,
"age_15_64": age1564,
"age_65_over": age65Over,
;
在这里我制作了年龄图表,该图表为我提供了来自 api 的 url 并放入未来的构建器中
ages_chart.dart
class AgeCharts extends StatefulWidget
final String url;
const AgeCharts(this.url);
@override
_AgeChartsState createState() => _AgeChartsState();
class _AgeChartsState extends State<AgeCharts>
var chart;
@override
void initState()
// TODO: implement initState
super.initState();
@override
Widget build(BuildContext context)
print(widget.url);
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text('Japanese Age Working Populations'),
),
body: Container(
height: 400,
child: FutureBuilder<List>(
future: getChartData(widget),
builder: (context, dataapi)
if (dataapi.hasError) print(dataapi.error);
print(dataapi);
return dataapi.hasData
? ShowChart(
data: dataapi.data,
)
: Center(
child: CircularProgressIndicator(),
);
,
),
),
),
);
在 dart 之后,我做了一个函数来获取一个 api。
Future<List> getChartData(widget) async
final response = await http.get(widget.url);
return json.decode(response.body)['data'];
这是我已经获得网址时的显示图表
class ShowChart extends StatelessWidget
final List data;
ShowChart(this.data);
static List<charts.Series<Ages, dynamic>> _createSampleData(dataAPI)
return [
new charts.Series<Ages, dynamic>(
id: 'Desktop',
// colorFn specifies that the line will be blue.
colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault,
// areaColorFn specifies that the area skirt will be light blue.
areaColorFn: (_, __) =>
charts.MaterialPalette.blue.shadeDefault.lighter,
domainFn: (Ages ages, _) => ages.year,
measureFn: (Ages ages, _) => int.parse(ages.underAge15),
data: dataAPI,
),
new charts.Series<Ages, dynamic>(
id: 'Tablet',
// colorFn specifies that the line will be red.
colorFn: (_, __) => charts.MaterialPalette.red.shadeDefault,
// areaColorFn specifies that the area skirt will be light red.
areaColorFn: (_, __) => charts.MaterialPalette.red.shadeDefault.lighter,
domainFn: (Ages ages, _) => ages.year,
measureFn: (Ages ages, _) => int.parse(ages.age1564),
data: dataAPI,
),
new charts.Series<Ages, dynamic>(
id: 'Mobile',
// colorFn specifies that the line will be green.
colorFn: (_, __) => charts.MaterialPalette.green.shadeDefault,
// areaColorFn specifies that the area skirt will be light green.
areaColorFn: (_, __) =>
charts.MaterialPalette.green.shadeDefault.lighter,
domainFn: (Ages ages, _) => ages.year,
measureFn: (Ages ages, _) => int.parse(ages.age65Over),
data: dataAPI,
),
];
@override
Widget build(BuildContext context)
print('showchart');
print(data);
return Container(
child: charts.LineChart(
_createSampleData(data),
defaultRenderer:
new charts.LineRendererConfig(includeArea: true, stacked: true),
animate: true,
),
);
这是我的 JSON 结构。但是我在使用 json.decode(response.body) 时得到了数据
"status": true,
"message": "Chart found",
"data": [
"entity": "Japan",
"code": "JPN",
"year": 1950,
"under_age_15": "29288.106",
"age_15_64": "49447.555",
"age_65_over": "4066.423"
,
"entity": "Japan",
"code": "JPN",
"year": 1951,
"under_age_15": "29652.515",
"age_15_64": "50461.828",
"age_65_over": "4201.922"
,
]
我遇到了这样的错误
type 'List<dynamic>' is not a subtype of type 'List<Ages>'
请帮我解决问题
【问题讨论】:
【参考方案1】:代码中的问题:
-
您将系列数据显式转换为
charts.Series<Ages, dynamic>
,而它应该是charts.Series<Ages, num>
您正试图将 double 解析为 int。如果你想要双打,使用 double.parse(x)
否则,double.parse(x).round()
会给你一个 int。 (或.floor()
或.ceil()
)
您可能还应该将域轴指定为非 zeroBound:
charts.LineChart(
_createSampleData(data),
defaultRenderer: charts.LineRendererConfig(includeArea: true, stacked: true),
animate: true,
domainAxis: charts.NumericAxisSpec(
tickProviderSpec: charts.BasicNumericTickProviderSpec(zeroBound: false),
),
),
工作解决方案
完整的源代码,方便复制粘贴
import 'dart:math' as math;
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart' as charts;
void main()
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Charts Demo',
home:
AgeCharts(url: 'http://udacoding-task-api.herokuapp.com/api/charts'),
),
);
// MAIN WIDGET
class AgeCharts extends StatefulWidget
final String url;
const AgeCharts(this.url);
@override
_AgeChartsState createState() => _AgeChartsState();
class _AgeChartsState extends State<AgeCharts>
var chart;
Future<List<Ages>> getChartData(widget) async
final response = await http.get(widget.url);
final List<dynamic> jsonData = jsonDecode(response.body)['data'];
return jsonData.map((data) => Ages.fromJson(data)).toList();
@override
Widget build(BuildContext context)
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text('Japanese Age Working Populations'),
),
body: Padding(
padding: EdgeInsets.all(8.0),
child: FutureBuilder<List>(
future: getChartData(widget),
builder: (context, dataapi)
if (dataapi.hasError) print(dataapi.error);
return dataapi.hasData
? ShowChart(data: dataapi.data)
: Center(child: CircularProgressIndicator());
,
),
),
),
);
// CHART
class ShowChart extends StatelessWidget
final List<Ages> data;
ShowChart(this.data);
static List<charts.Series<Ages, num>> _createSampleData(dataAPI)
return [
new charts.Series<Ages, num>(
id: 'underAge15',
colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault,
areaColorFn: (_, __) =>
charts.MaterialPalette.blue.shadeDefault.lighter,
domainFn: (Ages ages, _) => ages.year,
measureFn: (Ages ages, _) => double.parse(ages.underAge15).round(),
data: dataAPI,
),
new charts.Series<Ages, num>(
id: 'age1564',
colorFn: (_, __) => charts.MaterialPalette.red.shadeDefault,
areaColorFn: (_, __) => charts.MaterialPalette.red.shadeDefault.lighter,
domainFn: (Ages ages, _) => ages.year,
measureFn: (Ages ages, _) => double.parse(ages.age1564).round(),
data: dataAPI,
),
new charts.Series<Ages, num>(
id: 'age65Over',
colorFn: (_, __) => charts.MaterialPalette.green.shadeDefault,
areaColorFn: (_, __) =>
charts.MaterialPalette.green.shadeDefault.lighter,
domainFn: (Ages ages, _) => ages.year,
measureFn: (Ages ages, _) => double.parse(ages.age65Over).round(),
data: dataAPI,
),
];
@override
Widget build(BuildContext context)
return Container(
child: charts.LineChart(
_createSampleData(data),
defaultRenderer:
new charts.LineRendererConfig(includeArea: true, stacked: true),
animate: true,
domainAxis: charts.NumericAxisSpec(
tickProviderSpec:
charts.BasicNumericTickProviderSpec(zeroBound: false),
),
),
);
// DOMAIN
class Ages
Ages(
this.entity,
this.code,
this.year,
this.underAge15,
this.age1564,
this.age65Over,
);
String entity;
String code;
int year;
String underAge15;
String age1564;
String age65Over;
factory Ages.fromJson(Map<String, dynamic> json) => Ages(
entity: json["entity"],
code: json["code"],
year: json["year"],
underAge15: json["under_age_15"],
age1564: json["age_15_64"],
age65Over: json["age_65_over"],
);
Map<String, dynamic> toJson() =>
"entity": entity,
"code": code,
"year": year,
"under_age_15": underAge15,
"age_15_64": age1564,
"age_65_over": age65Over,
;
// DATA
math.Random random = math.Random();
final Map<String, dynamic> data =
"status": true,
"message": "Chart found",
"data": List.generate(
20,
(index) =>
"entity": "Japan",
"code": "JPN",
"year": 1950 + index,
"under_age_15": (25000 + random.nextInt(5000)).toString(),
"age_15_64": (40000 + random.nextInt(5000)).toString(),
"age_65_over": (3000 + random.nextInt(2000)).toString(),
).toList(),
;
答案更新前:
试试这个:
Future<List<Ages>> getChartData(widget) async
final response = await http.get(widget.url);
return json.decode(response.body)['data'].map((jsonData) => Ages.fromJson(jsonData)).toList();
我不能 100% 确定,因为我不知道您的 JSON 数据的结构。
【讨论】:
感谢您的回答,我已经编辑了我的问题:D 在我将 api 更改为您的答案后,我又遇到了另一个错误,类型 'List以上是关于Flutter - 对带有模型的图表使用 API的主要内容,如果未能解决你的问题,请参考以下文章
我可以在 Flutter 中使用类似 MPAndroidChart 的图表吗? [关闭]