Menu
CoddyTech

Weather App: Right Now

Part of the Data and the Network section of Coddy's Flutter journey. Lesson 23 of 27.

Time to build a whole app from this section: a weather app. Over the next five lessons it shows the weather for a city right now, the next three days, an icon for each, an error screen with Try again, and a city picker.

The practice API knows three cities. /weather/lisbon answers:

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

Start with the top of the screen, and the steps you know: a class for the data, a function that fetches and decodes it, a future made once in initState, and a FutureBuilder with its three states. The Weather and DayForecast classes at the bottom of the file are written for you, with their fromJson. This lesson shows the current weather; the forecast comes in the next one.

challenge icon

Challenge

Hard

Show Lisbon's weather:

  • loadWeather fetches /weather/lisbon and returns Weather.fromJson(jsonDecode(body))
  • make the future once in initState
  • a FutureBuilder<Weather> shows a spinner while it loads, Could not load: and the error if it fails
  • with the data, a Column of the city (size 32), the temperature with a degree sign, 21° (size 72, bold), and the condition (size 24)

Try it yourself

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 iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Data and the Network

Practice on your own: Online Flutter compiler