Menu
CoddyTech

Ứng dụng thời tiết: biểu tượng thời tiết

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

Mọi người đọc biểu tượng mặt trời nhanh hơn từ Sunny. Chuyển mỗi điều kiện thành một biểu tượng bằng một hàm, rồi dùng hàm đó ở mọi nơi hiển thị điều kiện.

Biểu thức switch chọn một giá trị cho mỗi trường hợp, còn _ dùng cho mọi trường hợp khác:

IconData iconFor(String condition) {
  return switch (condition) {
    'Sunny' => Icons.wb_sunny,
    'Cloudy' => Icons.cloud,
    _ => Icons.help_outline,
  };
}

Các trường hợp phải khớp chính xác với văn bản từ máy chủ, kể cả chữ hoa: 'sunny' sẽ không bao giờ khớp với Sunny. Trường hợp _ giúp ứng dụng tiếp tục hoạt động nếu một ngày nào đó máy chủ gửi một điều kiện mà bạn chưa dự tính.

challenge icon

Thử thách

Trung bình

Thêm biểu tượng:

  • một phương thức iconFor: Sunny là Icons.wb_sunny, Cloudy là Icons.cloud, Rainy là Icons.umbrella, Snowy là Icons.ac_unit, các trường hợp khác là Icons.help_outline
  • bên dưới thành phố, biểu tượng cho điều kiện hiện tại, kích thước 96, Colors.orange
  • ở đầu mỗi hàng dự báo, biểu tượng của ngày đó, sau đó chừa khoảng cách 16 pixel

Tự làm thử

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:intl/intl.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)),
        const SizedBox(height: 32),
        for (final day in weather.forecast)
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 8),
            child: Row(
              children: [
                Expanded(
                  child: Text(
                    DateFormat('EEEE').format(day.date),
                    style: const TextStyle(fontSize: 18),
                  ),
                ),
                Text('${day.high}° / ${day.low}°', style: const TextStyle(fontSize: 18)),
              ],
            ),
          ),
      ],
    );
  }
}

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