【问题标题】:How to sort Json Api data?如何对 Json Api 数据进行排序?
【发布时间】:2022-01-11 11:51:15
【问题描述】:

我正在尝试根据从 JSON API 获得的数据按日期对列表进行排序。 JSON 是一个被序列化为模型的 Map。我尝试了几件事,但都没有奏效。知道该怎么做吗?不确定是否应该在 Listview.builder 或 API 请求类中对其进行排序。

API 请求类

import 'package:http/http.dart' as http;
import 'package:lets_chat/app/modules/events/models/events.dart';



class EventApi {
  static var client = http.Client();


  static Future<Event?> fetchEvents() async {
    final response = await client.get(Uri.parse(
        'https://xposure.ae/wp-json/wp/auditorium/v1/events'));
    if (response.statusCode == 200) {
      var jsonString = response.body;
      return eventFromJson(jsonString);
    } else {
      //show error message
      return null;
    }
  }
}

模型类

import 'package:meta/meta.dart';
import 'dart:convert';

Event eventFromJson(String str) => Event.fromJson(json.decode(str));

String eventToJson(Event data) => json.encode(data.toJson());

class Event {
  Event({
    @required this.data,
  });

  List<Datum>? data;

  @override
  void initState() {
    data!.sort((a, b) => a.datetime.compareTo(b.datetime));
  }


  factory Event.fromJson(Map<String, dynamic> json) => Event(
    data: json["data"] == null ? null : List<Datum>.from(json["data"].map((x) => Datum.fromJson(x))),
  );

  Map<String, dynamic> toJson() => {
    "data": data == null ? null : List<dynamic>.from(data!.map((x) => x.toJson())),
  };
}

class Datum {
  Datum({
    required this.eventtitle,
    required this.description,
    required this.eventImage,
    required this.speaker,
    required this.datetime,
    required this.location,
  });

  String eventtitle;
  String description;
  String eventImage;
  Speaker? speaker;
  String datetime;
  Location? location;


  factory Datum.fromJson(Map<String, dynamic> json) => Datum(
    eventtitle: json["Eventtitle"] == null ? null : json["Eventtitle"],
    description: json["Description"] == null ? null : json["Description"],
    eventImage: json["event_image"] == null ? null : json["event_image"],
    speaker: json["Speaker"] == null ? null : Speaker.fromJson(json["Speaker"]),
    datetime: json["datetime"] == null ? null : json["datetime"],
    location: json["Location"] == null ? null : Location.fromJson(json["Location"]),
  );

  Map<String, dynamic> toJson() => {
    "Eventtitle": eventtitle == null ? null : eventtitle,
    "Description": description == null ? null : description,
    "event_image": eventImage == null ? null : eventImage,
    "Speaker": speaker == null ? null : speaker!.toJson(),
    "datetime": datetime == null ? null : datetime,
    "Location": location == null ? null : location!.toJson(),
  };
}

class Location {
  Location({
    required this.venue,
    required this.address,
  });

  Venue? venue;
  Address? address;

  factory Location.fromJson(Map<String, dynamic> json) => Location(
    venue: json["venue"] == null ? null : venueValues.map[json["venue"]],
    address: json["address"] == null ? null : addressValues.map[json["address"]],
  );

  Map<String, dynamic> toJson() => {
    "venue": venue == null ? null : venueValues.reverse[venue],
    "address": address == null ? null : addressValues.reverse[address],
  };
}

enum Address { SHARJAH_BR_SHARJAH_BR_61110_BR_UNITED_ARAB_EMIRATES }

final addressValues = EnumValues({
  "Sharjah</br>Sharjah,</br>61110,</br>United Arab Emirates": Address.SHARJAH_BR_SHARJAH_BR_61110_BR_UNITED_ARAB_EMIRATES
});

enum Venue { XPOSURE_INTERNATIONAL_PHOTOGRAPHY_FESTIVAL }

final venueValues = EnumValues({
  "Xposure International Photography Festival": Venue.XPOSURE_INTERNATIONAL_PHOTOGRAPHY_FESTIVAL
});

class Speaker {
  Speaker({
    required this.speakername,
    required this.link,
  });

  String speakername;
  String link;

  factory Speaker.fromJson(Map<String, dynamic> json) => Speaker(
    speakername: json["speakername"] == null ? null : json["speakername"],
    link: json["link"] == null ? null : json["link"],
  );

  Map<String, dynamic> toJson() => {
    "speakername": speakername == null ? null : speakername,
    "link": link == null ? null : link,
  };
}

class EnumValues<T> {
  Map<String, T> map;
  late Map<T, String> reverseMap;

  EnumValues(this.map);

  Map<T, String> get reverse {
    if (reverseMap == null) {
      reverseMap = map.map((k, v) => new MapEntry(v, k));
    }
    return reverseMap;
  }
}

偶数视图类

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/instance_manager.dart';
import 'package:lets_chat/app/modules/events/views/event_details.dart';
import 'package:lets_chat/app/modules/events/controllers/events_controller.dart';
import 'package:lets_chat/app/modules/events/views/event_tile.dart';

class EventView extends StatelessWidget {
  final EventsController eventController = Get.put(EventsController());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey[800],
      appBar: AppBar(
        backgroundColor: Colors.grey[850],
        elevation: 2,
        leading: GestureDetector(
          onTap: () {
            Navigator.pop(context);
          },
          child: const Icon(
            Icons.arrow_back_ios,
            color: Colors.grey,
          ),
        ),
      ),
      body: Column(
        children: [
          Expanded(
            child: Obx(() {
              if (eventController.isLoading.value)
                return Center(child: CircularProgressIndicator(
                  color: Colors.red,
                ));
              else {
                return ListView.builder(
                    itemCount: eventController.event.value!.data!.length,
                    itemBuilder: (context, index) {
                      return GestureDetector(
                        onTap: () {
                          Navigator.push(
                            context, MaterialPageRoute(builder: (context) => EventDetails(event: eventController.event.value!.data![index]))
                          );
                        },
                          child: EventTile(eventController.event.value!.data![index]));
                    });
              }
            }),
          )
        ],
      ),
    );
  }
}

【问题讨论】:

    标签: json flutter api dart


    【解决方案1】:

    看来您在 Model 类中将日期存储为 String

    然后按字母顺序排序:

    void main() {
      List<String> dates = [
        "September 14, 2022 - 2:35 PM",
        "February 24, 2022 - 3:05 AM",
        "February 3, 2022 - 10:10 AM",
        "January 13, 2022 - 9:15 PM"
      ];
      dates.sort((a, b) => a.compareTo(b));
      dates.forEach(print);
    }
    
    // Dates get sorted alphabetically:
    // February 24, 2022 - 3:05 pm
    // February 3, 2022 - 10:10 pm
    // January 13, 2022 - 9:15 pm
    // September 14, 2022 - 2:35 pm
    

    如果这是您面临的问题,您可能应该在您的 sort 或(可能更好)在您的 fromJson 转换中将它们转换为 DateTime 对象。

    简单示例:

    void main2() {
      List<DateTime> dates = [
        "September 14, 2022 - 2:35 PM",
        "February 24, 2022 - 3:05 AM",
        "February 3, 2022 - 10:10 AM",
        "January 13, 2022 - 9:15 PM"
      ].map((d) => DateFormat('MMMM d, y - h:mm a').parse(d)).toList();
      dates.sort((a, b) => a.compareTo(b));
      dates.forEach(print);
    }
    
    // Dates get sorted chronologically:
    // 2022-01-13 21:15:00.000
    // 2022-02-03 10:10:00.000
    // 2022-02-24 03:05:00.000
    // 2022-09-14 14:35:00.000
    

    【讨论】:

      【解决方案2】:

      这里是如何对来自 JSON API 的数据进行排序。

       Widget build(BuildContext context) {
      return MaterialApp(
        home: Scaffold(
            appBar: AppBar(
              title: Text("Events",
                  style: TextStyle(color: Colors.black, fontSize: 16)),
              backgroundColor: Color(0xffffffff),
              elevation: 0.0,
              actions: [
                TextButton.icon(
                    icon: Icon(
                      Icons.refresh,
                      color: Colors.black,
                    ),
                    onPressed: () {
                      if (ascend) {
                        sortAscending(); //to sort the date from oldest to latest
                      } else {
                        sortDescending(); //to sort the date from latest to oldest
                      }
                    },
                    label: Text(
                      "Sort by date",
                      style: TextStyle(fontSize: 11, color: Colors.black),
                    ))
              ],
            ),
            body: SingleChildScrollView(
              child: Padding(
                padding: EdgeInsets.only(left: 5),
                child: Column(
                  children: _buildList(),
                ),
              ),
            )),
        debugShowCheckedModeBanner: false,
      );
      

      }

      下面的代码可以帮助你构建一个小部件数组

       List<Widget> _buildList() {
      List<Widget> x = [];
      
      //jsonData refers to the data from the JSON API
       //sort the jsonData here before the loop by calling either the sortAscending() function or sortDescending() function.
      
      sortDescending(); //from latest date to oldest
      
      for (int i = 0; i < jsonData.length; i++) {
        DateTime dateTime =
            DateFormat("MMMM dd, yyyy - kk:mm").parse(jsonData[i]['datetime']);
      
        x.add(
          Row(children: [
            Flex(
                mainAxisAlignment: MainAxisAlignment.center,
                direction: Axis.vertical,
                children: [
                  Text(months[dateTime.month - 1].toString(),
                      style:
                          TextStyle(fontWeight: FontWeight.bold, fontSize: 14)),
                  Card(
                    child: Container(
                        padding: const EdgeInsets.all(8.0),
                        child: Flex(direction: Axis.vertical, children: [
                          Text(
                            dateTime.day.toString(),
                            style: TextStyle(
                                fontWeight: FontWeight.bold,
                                color: Color(0xff800200),
                                fontSize: 22),
                          ),
                          Padding(
                            padding: EdgeInsets.only(top: 5),
                            child: Text(
                              dateTime.year.toString(),
                              style: TextStyle(fontSize: 11),
                            ),
                          )
                        ])),
                  ),
                ]),
            Flexible(
              child: Card(
                semanticContainer: true,
                clipBehavior: Clip.antiAliasWithSaveLayer,
                child: Container(
                  height: 200,
                  decoration: new BoxDecoration(
                    image: new DecorationImage(
                      image: NetworkImage(jsonData[i]['event_image']),
                      fit: BoxFit.fill,
                      colorFilter: new ColorFilter.mode(
                          Colors.black.withOpacity(0.25), BlendMode.dstATop),
                    ),
                  ),
                  child: Padding(
                    padding: EdgeInsets.only(right: 10, left: 10, bottom: 5),
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.end,
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(jsonData[i]['Eventtitle'],
                            style: TextStyle(fontWeight: FontWeight.w800)),
                        SizedBox(
                          height: 5,
                        ),
                        Row(
                          children: [
                            Icon(
                              Icons.pin_drop,
                              color: Colors.black54,
                            ),
                            Text(
                              jsonData[i]['Location']['venue'],
                              style: TextStyle(fontSize: 13),
                            )
                          ],
                        )
                      ],
                    ),
                  ),
                ),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(10.0),
                ),
                elevation: 5,
                margin: EdgeInsets.all(10),
              ),
            )
          ]),
        );
      }
      
      return x;
      

      }

      当您使用 AppBar 上的操作按钮按日期排序时,以下功能将有助于更新列表

        sortAscending() {
      setState(() {
        ascend = false; //initialize this bool variable at the top of the class.
        jsonData.sort((a, b) => DateFormat("MMMM dd, yyyy - kk:mm")
            .parse(b['datetime'])
            .compareTo(DateFormat("MMMM dd, yyyy - kk:mm").parse(a['datetime'])));
      });
      

      }

        sortDescending() {
      setState(() {
        ascend = true;
        jsonData.sort((a, b) => DateFormat("MMMM dd, yyyy - kk:mm")
            .parse(a['datetime'])
            .compareTo(DateFormat("MMMM dd, yyyy - kk:mm").parse(b['datetime'])));
      });
      

      }

      您将在下面使用来格式化月份的名称。

      List months = [  'JAN',  'FEB',  'MAR',  'APR',  'MAY',  'JUN',  'JUL',  'AUG', 'SEP',  'OCT',  'NOV',  'DEC'];
      

      以下是说明截图:

      【讨论】:

      • 感谢您为我解决问题的答案。你知道我该如何设置当用户进入该事件页面时列表已经按日期排序?
      • 嗨@Quentinio,是的,这是可能的。我更新了 _buildList() 函数。在 for 循环之前,添加了一个代码以在显示之前对列表进行排序。也请赞成我的答案。谢谢。
      • 谢谢!我想投票,但我的水平不够高:/
      • 酷,我明白了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-04
      • 1970-01-01
      • 2015-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多