繁体   English   中英

Flutter:如何根据 TabBar 和 ToggleButtons 从 JSON 过滤数据?

[英]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
  }
]

我想按如下方式显示过滤后的数据:

在此处输入图像描述

  1. 第一个过滤器是TabBar ("continentName")
  2. 第二个过滤器是ToggleButtons ("isDayTime") =>需要至少一个选择
  3. 第三个过滤器是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:

我想添加以下两件事:

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

在此处输入图像描述

  • 我使用来自 JSON: xAlign & yAlign的数据来确定图像上 cityName 的cityName (JSON 更新)
  • 据我所知,似乎最好的方法是使用IntrinsicHeightStackAlign来做这样的事情:
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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM