[英]Flutter: How to filter data from JSON based on TabBar and ToggleButtons?
我有一个像这样的 JSON:
[
{
"continentName": "NA",
"isDayTime": true,
"seasonName": "Spring",
"cityName": "United States",
"xAlign": 45.4,
"yAlign": 69,
"cityTemperature": 27
},
{
"continentName": "NA",
"isDayTime": true,
"seasonName": "Spring",
"cityName": "Canada",
"xAlign": 35.7,
"yAlign": 53,
"cityTemperature": 16
},
{
"continentName": "NA",
"isDayTime": true,
"seasonName": "Summer",
"cityName": "Mexico",
"xAlign": 87.8,
"yAlign": 41.8,
"cityTemperature": 28
},
{
"continentName": "NA",
"isDayTime": false,
"seasonName": "Summer",
"cityName": "Cuba",
"xAlign": 55.3,
"yAlign": 88.8,
"cityTemperature": 27
},
{
"continentName": "EU",
"isDayTime": true,
"seasonName": "Winter",
"cityName": "Germany",
"xAlign": 33.8,
"yAlign": 38.8,
"cityTemperature": 3
}
]
我想按如下方式显示过滤后的数据:
TabBar
("continentName")ToggleButtons
("isDayTime") =>需要至少一个选择ToggleButtons
("listSeason") =>互斥选择,但不允许选择任何按钮。 启动页面时,默认情况下Tabbar
选择为“NA”,第一个toggleButtons
(“isDayTime”)选择为“Day”=>我希望如果点击“Spring”=>它将显示令人满意的数据,特别是这里将是“美国”和“加拿大”
所以请帮助我,这是主文件:
import 'package:ask/model/temperature_model.dart';
import 'package:ask/services/temperature_service.dart';
import 'package:flutter/material.dart';
class CityTemperature extends StatefulWidget {
CityTemperature() : super();
@override
_CityTemperatureState createState() => _CityTemperatureState();
}
class _CityTemperatureState extends State<CityTemperature> {
List<Temperature> _temperature = [];
List<bool> isDayTime = [true, false];
List<bool> listSeason = [false, false, false, false];
@override
void initState() {
super.initState();
TemperatureServices.getTemperature().then((temperature) {
setState(() {
_temperature = temperature;
});
});
}
@override
Widget build(BuildContext context) {
return Container(
child: DefaultTabController(
length: 4,
child: Scaffold(
appBar: AppBar(
title: Text('Temperature'),
bottom: TabBar(tabs: [
Tab(child: Text('NA')),
Tab(child: Text('EU')),
Tab(child: Text('Africa')),
Tab(child: Text('Asia')),
]),
),
body: Column(children: [
Center(
child: ToggleButtons(
children: [Text('Day'), Text('Night')],
onPressed: (int index) {
setState(() {
for (int buttonIndex = 0; buttonIndex < isDayTime.length; buttonIndex++) {
if (buttonIndex == index) {
isDayTime[buttonIndex] = true;
} else {
isDayTime[buttonIndex] = false;
}
}
});
},
isSelected: isDayTime)),
SizedBox(height: 5),
Center(
child: ToggleButtons(
children: [Text('Spring'), Text('Summer'), Text('Autumn'), Text('Winter')],
onPressed: (int index) {
setState(() {
for (int buttonIndex = 0; buttonIndex < listSeason.length; buttonIndex++) {
if (buttonIndex == index) {
listSeason[buttonIndex] = !listSeason[buttonIndex];
} else {
listSeason[buttonIndex] = false;
}
}
});
},
isSelected: listSeason)),
SizedBox(height: 5),
Expanded(
child: TabBarView(children: [
Column(children: [ // How to display the satisfying data
for (Temperature temp in _temperature)
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(temp.cityName),
Text('${temp.cityTemperature.toString()}° C'),
],
)
]),
Column(), // How to display the satisfying data
Column(), // How to display the satisfying data
Column(), // How to display the satisfying data
]),
)
]))));
}
}
我想添加以下两件事:
1.在TabBarView
中为每个_tabs
和每个isDayTime
添加背景图片
continentName
,将有 2 张图片代表白天或夜晚。Assets
中,以便用户加载更快。 此外,为了避免在 json 上创建更多数据 => 我将创建图像的文件名为:“na_day.png”或“na_true.png”并通过以下方式访问它: Image.asset('assets/${temp.continentName}_${isDayTime}.png')
或类似的东西 2.根据图片的XY百分比position在背景图片上显示cityName
xAlign
& yAlign
的数据来确定图像上 cityName 的cityName
(JSON 更新)IntrinsicHeight
, Stack
和Align
来做这样的事情:class DisplayCountry extends StatelessWidget {
final List<Temperature> countries;
DisplayCountry({this.countries});
@override
Widget build(BuildContext context) {
return Column(children: [
for (Temperature temp in countries) // I don't know where to put this
IntrinsicHeight(
child: Stack(children: [
Image.asset('assets/${temp.continentName}_${isDayTime}.png'.asset), // Or something like this
Align(
alignment: Alignment(temp.xAlign / 100 * 2 - 1, temp.yAlign / 100 * 2 - 1),
child: Text(temp.cityName),
),
]),
)
]);
}
}
extension AssetsExtension on String {
String get asset => this.toLowerCase().replaceAll(" ", "_").replaceAll("'", "_");
}
所以请帮我更新class DisplayCountry
以便能够结合上述两件事
像这样的东西
class CityTemperature extends StatefulWidget {
CityTemperature() : super();
@override
_CityTemperatureState createState() => _CityTemperatureState();
}
class _CityTemperatureState extends State<CityTemperature> {
List<Temperature> _temperature = [];
List<String> _tabs = [];
Map<String, bool> isDayTime = {'Day': true, 'Night': false};
Map<String, bool> listSeason = {'Spring': false, 'Summer': false, 'Autumn': false, 'Winter': true};
@override
void initState() {
super.initState();
var response = json.decode(jsonFile);
_temperature = List<Temperature>.from(response.map((x) => Temperature.fromJson(x)));
_tabs = _temperature.map<String>((x) => x.continentName).toSet().toList();
/*
TemperatureServices.getTemperature().then((temperature) {
setState(() {
_temperature = temperature;
});
});*/
}
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: _tabs.length,
child: Scaffold(
appBar: AppBar(
title: Text('Temperature'),
bottom: TabBar(
tabs: _tabs.map((String name) => Tab(text: name)).toList()
),
),
body: Column(children: [
Center(
child: ToggleButtons(
children: isDayTime.keys.map((key) => Text(key)).toList(),
onPressed: (int index) {
String indexKey = isDayTime.keys.toList()[index];
setState(() {
isDayTime.updateAll(
(key, value) => key == indexKey ? true : false);
}
);
},
isSelected: isDayTime.values.toList())),
SizedBox(height: 5),
Center(
child: ToggleButtons(
children: listSeason.keys.map((key) => Text(key)).toList(),
onPressed: (int index) {
String indexKey = listSeason.keys.toList()[index];
setState(() {
listSeason.updateAll(
(key, value) => key == indexKey ?
!listSeason[indexKey] : false);
});
},
isSelected: listSeason.values.toList())),
SizedBox(height: 5),
Expanded(
child: TabBarView(
children: _tabs.map((String name) {
return DisplayCountry(
countries: List<Temperature>.from(_temperature)
..retainWhere((temperature) =>
temperature.continentName == name
&& temperature.isDayTime == isDayTime['Day']
&& temperature.seasonName == listSeason.keys.firstWhere(
(k) => listSeason[k] == true, orElse: () => 'Nothing'))
);
}).toList()
),
)
]
)
)
);
}
}
class DisplayCountry extends StatelessWidget{
final List<Temperature> countries;
DisplayCountry({this.countries});
@override
Widget build(BuildContext context){
return Column(
children: [
for(Temperature temp in countries)
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(temp.cityName),
Text('${temp.cityTemperature.toString()}° C'),
],
)
]
);
}
}
我创建了一个名为 _tabs 的列表,其中包含 _temperatures 的所有大陆名称,然后添加了 toSet 和 toList。 toSet 将其转换为一个集合,一个集合是一个不允许重复值的可迭代对象,然后我将其转换回列表,这样我就有了一个唯一大陆名称(NA、EU 等)的列表。
在 DefaultTabController 我添加 _tabs.length 并在 tabView 我创建一个 _tab.map 列表,它创建一个 DisplayCountry 小部件列表,我使用retainwhere 只保留满足条件的那些(与选项卡中的相同的continentName,与选择的季节名称相同的季节名称,如果为真,则为白天时间,否则为白天)
更新
class DisplayImage extends StatelessWidget {
final List<Temperature> countries;
final String continentName;
final bool isDayTime;
DisplayImage({this.countries , this.continentName, this.isDayTime});
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Stack(
fit: StackFit.passthrough,
children: [
Image.asset('assets/$continentName_$isDayTime.png'.asset),
fit: BoxFit.cover,),
for (Temperature temp in countries)
Positioned(
left: temp.xAlign * size.width / 100.0,
top: temp.yAlign / 2 * size.height / 100.0,
child: Text('${temp.cityName} ${temp.cityTemperature.toString()}° C'),
)
]);
}
}
并在 TabView 中调用它时
TabBarView(
children: _tabs.map((String name) {
return DisplayImage(
continentName: name,
isDayTime: isDayTime['Day'],
countries: List<Temperature>.from(_temperature)
..retainWhere((temperature) =>
temperature.continentName == name &&
temperature.isDayTime == isDayTime['Day'] &&
temperature.seasonName ==
listSeason.keys.firstWhere(
(k) => listSeason[k] == true,
orElse: () => 'Nothing')));
}).toList())
据我了解,您可以使用堆栈的 fit 属性(StackFit.passthrough),它的工作原理与intrinsicHeight 相同。 从文档
StackFit.passthrough
For example, if a Stack is an Expanded child of a Row, the horizontal constraints will be tight and the vertical constraints will be loose.
在这种情况下,您在列中使用 Expanded,因此它具有水平松散和垂直紧缩。 然后做一些数学运算并尝试 Align 小部件,如果定位不按你想要的那样工作
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.