Menu
CoddyTech

Ứng dụng thời tiết: ba ngày tới

Thuộc phần Dữ liệu và mạng trong hành trình Flutter của Coddy. Bài học 24 trên 27.

Kết quả cho một thành phố cũng có dự báo: một danh sách JSON nằm trong đối tượng, mỗi mục ứng với một ngày.

"forecast": [
  {"date": "2026-10-20", "condition": "Cloudy", "high": 22, "low": 15},
  ...
]

Danh sách bên trong đối tượng được đọc giống như một danh sách riêng: lấy nó ra bằng as List<dynamic>, rồi dùng map để chuyển từng mục qua fromJson riêng của mục đó. Xem Weather.fromJson ở cuối tệp: hàm này đã làm việc đó, nên weather.forecast là một List<DayForecast>.

final days = json['forecast'] as List<dynamic>;

forecast: days
    .map((day) => DayForecast.fromJson(day as Map<String, dynamic>))
    .toList(),

Mỗi ngày có một DateTime. DateFormat('EEEE') chuyển nó thành tên đầy đủ của ngày trong tuần, Tuesday. Một vòng lặp for bên trong phần tử children của Column tạo một hàng cho mỗi ngày.

challenge icon

Thử thách

Trung bình

Bên dưới thời tiết hiện tại, hãy hiển thị dự báo cho ba ngày tiếp theo:

  • import package:intl/intl.dart
  • sau một SizedBox(height: 32), tạo một Row cho mỗi ngày: hiển thị thứ trong tuần bằng DateFormat('EEEE') trong một Expanded, sau đó hiển thị nhiệt độ cao nhất và thấp nhất theo dạng 22° / 15°
  • thêm khoảng đệm 32 pixel ở bên trái và bên phải của mỗi hàng

Tự làm thử

import 'dart:convert';

import 'package:flutter/material.dart';

import 'api.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: WeatherScreen(),
    );
  }
}

class WeatherScreen extends StatefulWidget {
  const WeatherScreen({super.key});

  @override
  State<WeatherScreen> createState() => _WeatherScreenState();
}

class _WeatherScreenState extends State<WeatherScreen> {
  late Future<Weather> _weather;

  @override
  void initState() {
    super.initState();
    _weather = loadWeather();
  }

  Future<Weather> loadWeather() async {
    final body = await fetch('/weather/lisbon');
    return Weather.fromJson(jsonDecode(body));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Weather')),
      body: Center(
        child: FutureBuilder<Weather>(
          future: _weather,
          builder: (context, snapshot) {
            if (snapshot.hasError) {
              return Text('Could not load: ${snapshot.error}');
            }
            if (snapshot.hasData) {
              return buildWeather(snapshot.data!);
            }
            return const CircularProgressIndicator();
          },
        ),
      ),
    );
  }

  Widget buildWeather(Weather weather) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Text(weather.city, style: const TextStyle(fontSize: 32)),
        Text(
          '${weather.temperature}°',
          style: const TextStyle(fontSize: 72, fontWeight: FontWeight.bold),
        ),
        Text(weather.condition, style: const TextStyle(fontSize: 24)),
      ],
    );
  }
}

class Weather {
  Weather({
    required this.city,
    required this.temperature,
    required this.condition,
    required this.forecast,
  });

  final String city;
  final int temperature;
  final String condition;
  final List<DayForecast> forecast;

  factory Weather.fromJson(Map<String, dynamic> json) {
    final days = json['forecast'] as List<dynamic>;
    return Weather(
      city: json['city'] as String,
      temperature: json['temperature'] as int,
      condition: json['condition'] as String,
      forecast: days
          .map((day) => DayForecast.fromJson(day as Map<String, dynamic>))
          .toList(),
    );
  }
}

class DayForecast {
  DayForecast({
    required this.date,
    required this.condition,
    required this.high,
    required this.low,
  });

  final DateTime date;
  final String condition;
  final int high;
  final int low;

  factory DayForecast.fromJson(Map<String, dynamic> json) {
    return DayForecast(
      date: DateTime.parse(json['date'] as String),
      condition: json['condition'] as String,
      high: json['high'] as int,
      low: json['low'] as int,
    );
  }
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Dữ liệu và mạng

Tự luyện tập: Trình biên dịch Flutter online