Menu
CoddyTech

天气应用:此刻

本课属于 Coddy Flutter 学习旅程的“数据与网络”单元。第 23 课,共 27 课。

是时候用本单元的内容构建一个完整的应用了:天气应用。在接下来的 5 节课中,它会显示一个城市当前的天气、未来 3 天的天气、每天对应的图标、带有“再试一次”按钮的错误界面,以及城市选择器。

练习 API 支持 3 个城市。/weather/lisbon会返回:

{
  "city": "Lisbon",
  "temperature": 21,
  "condition": "Sunny",
  "forecast": [ ... ]
}

先从屏幕顶部开始,按照你已经掌握的步骤来做:创建一个用于存放数据的类,编写一个用于获取和解码数据的函数,在 initState 中创建一次 Future,并使用 FutureBuilder 处理它的 3 种状态。文件底部的 Weather 和 DayForecast 类及其 fromJson 已经为你编写好了。本课将显示当前天气,下一课会介绍天气预报。

challenge icon

挑战

困难

显示里斯本的天气:

  • loadWeather 获取 /weather/lisbon,并返回 Weather.fromJson(jsonDecode(body))
  • 在 initState 中创建一次 Future
  • FutureBuilder<Weather> 会在加载时显示加载指示器;如果加载失败,则显示 Could not load: 和错误信息
  • 有数据时,显示一个 Column,其中包括城市(字号 32)、带度数符号的温度 21°(字号 72、加粗)和天气状况(字号 24)

亲手试试

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> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Weather')),
      body: const Center(
        child: Text('The weather goes here'),
      ),
    );
  }
}

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 icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

数据与网络中的所有课

自己练习: Flutter 在线编译器