Flutter中如何将JSON转为Map<DateTime, List>适配Table Calendar插件
Hey there! Let's walk through how to convert your API response into the Map<DateTime, List> format that table_calendar expects, and load it into your _events variable during initState.
Step 1: Confirm Your Data Models
First, let's make sure your Post model is set up correctly to parse the API's date and title fields. Here's a typical implementation:
class Post { final String date; final String title; Post({required this.date, required this.title}); // Factory method to convert JSON to Post object factory Post.fromJson(Map<String, dynamic> json) { return Post( date: json['date'] as String, title: json['title'] as String, ); } }
Step 2: Implement the Conversion Logic in getTask
Your getTask method will fetch the API data, parse it into a list of Post objects, then convert that list into the required Map<DateTime, List<Post>> structure. Here's the updated method:
import 'dart:convert'; import 'package:http/http.dart' as http; // Inside your State class Map<DateTime, List<Post>> _events = {}; Future<void> getTask() async { try { // Replace with your actual API endpoint final response = await http.get(Uri.parse('your_api_endpoint_here')); if (response.statusCode == 200) { // Parse JSON response into a list of dynamic objects final List<dynamic> rawData = json.decode(response.body); // Convert raw JSON to List<Post> final List<Post> posts = rawData.map((json) => Post.fromJson(json)).toList(); // Initialize a temporary map to build our events structure final Map<DateTime, List<Post>> tempEvents = {}; for (final post in posts) { // Convert the string date from API to DateTime object // Adjust the parse format if your API uses a different date string (e.g., "MM/DD/YYYY") final DateTime rawDate = DateTime.parse(post.date); // table_calendar uses date-only DateTime keys (ignore time if present) final DateTime eventDate = DateTime(rawDate.year, rawDate.month, rawDate.day); // Add the post to the corresponding date in the map if (tempEvents.containsKey(eventDate)) { tempEvents[eventDate]!.add(post); } else { tempEvents[eventDate] = [post]; } } // Update the state with our converted events setState(() { _events = tempEvents; }); } else { throw Exception('Failed to load tasks: ${response.statusCode}'); } } catch (e) { print('Error fetching or parsing data: $e'); // Handle error (show snackbar, etc.) } }
Step 3: Load Data in initState
Call getTask when your widget initializes to populate _events:
@override void initState() { super.initState(); getTask(); }
Step 4: Use _events with table_calendar
Finally, pass the _events map to your TableCalendar widget. You'll use the eventLoader callback to provide events for each day:
TableCalendar( focusedDay: DateTime.now(), firstDay: DateTime(2024, 1, 1), lastDay: DateTime(2024, 12, 31), // Use the eventLoader to map days to their events eventLoader: (day) { // Return empty list if no events exist for the day return _events[day] ?? []; }, // Optional: Customize how events are displayed calendarBuilders: CalendarBuilders( markerBuilder: (context, day, events) { if (events.isNotEmpty) { return Positioned( bottom: 1, child: Container( width: 16, height: 16, decoration: BoxDecoration( color: Colors.blue, shape: BoxShape.circle, ), child: Center( child: Text( '${events.length}', style: TextStyle(color: Colors.white, fontSize: 12), ), ), ), ); } return null; }, ), )
Notes for Edge Cases
- Date Format Issues: If your API returns dates in a non-standard format (e.g., "2024/05/20" or "May 20, 2024"), use the
intlpackage'sDateFormatclass to parse them correctly. Addintlto yourpubspec.yaml, then:import 'package:intl/intl.dart'; final DateTime rawDate = DateFormat('yyyy/MM/dd').parse(post.date); - Duplicate Dates: The code automatically groups multiple posts under the same date, which is exactly what
table_calendarneeds.
内容的提问来源于stack exchange,提问作者user12456101

