Hava Durumu Uygulaması: Bir Şehir Seç
Coddy'nin Flutter Journey'sinin Veri ve Ağ bölümünün bir parçası. Ders 27 / 27.
Son özellik: üstte Lizbon, Tokyo ve Oslo şehirlerinden oluşan bir satır. Birine dokunmak o şehrin hava durumunu yükler.
Bir şehir seçmek, farklı bir yol kullanarak yeniden yükleme yapmaktır. Seçilen city değerini durumda tut, loadWeather işlevine bir parametre ver ve yolu bu değerden oluştur:
Future<Weather> loadWeather(String city) async {
final body = await fetch('/weather/${city.toLowerCase()}');
return Weather.fromJson(jsonDecode(body));
}Düğmelerde Tokyo yazar, ancak sunucunun yolu /weather/tokyo şeklindedir. toLowerCase() birini diğerine dönüştürür. Çoğu sunucuda yollar büyük-küçük harfe duyarlıdır; bu nedenle /weather/Tokyo için Not found sonucu alınır.
Düğme satırını FutureBuilder öğesinin dışına koy; böylece şehir yüklenirken ekranda kalır. Satırı üstte, FutureBuilder öğesini de altta bir Expanded içinde tutan bir Column bunu sağlar.
Görev
ZorBir şehir seçici ekle:
- durumda bir
String city = 'Lisbon';ve küçük harflerle yazılmış şehirle birlikte/weather/yolunu getirenloadWeather(String city) - gövdenin üst kısmında, üç
TextButtoniçeren ortalanmış birRow:Lisbon,Tokyo,Oslo - birine dokunmak,
setStateiçindecityve yeni bir_weatherdeğerini ayarlar - satırın altında, bir
ExpandediçindeFutureBuilderbulunur ve Tekrar dene seçilen şehri yeniden yükler
Kendin dene
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));
}
void tryAgain() {
setState(() {
_weather = loadWeather();
});
}
IconData iconFor(String condition) {
return switch (condition) {
'Sunny' => Icons.wb_sunny,
'Cloudy' => Icons.cloud,
'Rainy' => Icons.umbrella,
'Snowy' => Icons.ac_unit,
_ => Icons.help_outline,
};
}
@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.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
if (snapshot.hasError) {
return buildError(snapshot.error!);
}
return buildWeather(snapshot.data!);
},
),
),
);
}
Widget buildWeather(Weather weather) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(weather.city, style: const TextStyle(fontSize: 32)),
Icon(iconFor(weather.condition), size: 96, color: Colors.orange),
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: [
Icon(iconFor(day.condition)),
const SizedBox(width: 16),
Expanded(
child: Text(
DateFormat('EEEE').format(day.date),
style: const TextStyle(fontSize: 18),
),
),
Text('${day.high}° / ${day.low}°', style: const TextStyle(fontSize: 18)),
],
),
),
],
);
}
Widget buildError(Object error) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.cloud_off, size: 64),
const SizedBox(height: 16),
const Text('Could not load the weather', style: TextStyle(fontSize: 20)),
Text('$error'),
const SizedBox(height: 16),
ElevatedButton(onPressed: tryAgain, child: const Text('Try again')),
],
);
}
}
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,
);
}
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Veri ve Ağ bölümündeki tüm dersler
3Çağrılar Başarısız Olduğunda
try ile Hataları YakalamaHata Fırlatmafinally ile TemizlemeFutureBuilder Hata DurumuYeniden Dene Düğmesi6Proje: Hava Durumu Uygulaması
Hava Durumu Uygulaması: Şu AnHava Durumu Uygulaması: Önümüzdeki Üç GünKendi başına pratik yap: Online Flutter derleyicisi