FLUTTER İLE HAVA DURUMU UYGULAMASI

Merhabalar bugün size Flutter kullanarak yapmış olduğum basit bir hava durumu uygulamasını göstereceğim.




Bu uygulama ile API'dan veri çekip bunu ekrana basmayı öğreneceğiz.

Öncelikle bize şehir ararken yardımcı olması için AutoComplete widget'ını kullanacağız. Bu widget'a liste tipinde bir değişken vermemiz gerekiyor. Bunun için bir listeye tüm şehirleri atacağız. Bunu elle yapmayacağız, bir json dosyasından çekip listeye aktaracağız. Gerekli json dosyasına buradan ulaşabilirsiniz.

Bu json dosyasını indirdikten sonra flutter projemizin içine attık. Lib'in altında assets klasörü oluşturup onun içine atabilirsiniz. Bu json dosyasını asset olarak tanıtabilmemiz için pubspec.yaml dosyasının içine

assets:
- lib/assets/cities.json

ekliyoruz. Json dosyamızı tanıttıktan sonra sıra modelimizi oluşturmaya geldi.


class WeatherModel{
String city="";
String cityStatus="";
String cityWeather="";
WeatherModel({required this.city, required this.cityStatus, required this.cityWeather });
factory WeatherModel.fromJson(Map<String, dynamic> json) {
return WeatherModel(
city: json['name'],
cityStatus: json['weather'][0]['description'],
cityWeather: json['main']['temp'].toString(),
);
}
}
view raw model hosted with ❤ by GitHub

Modelimiz bu şekilde. Api'dan şehir ismi, sıcaklık değeri ve açıklamasını alacağımız için modelde 3 alan oluşturdum. Sıra servis dosyasını yazmaya geldi.

import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
import '../models/models.dart';
class ApiServices{
Future<WeatherModel> makeList({city})
async {
final url = Uri.parse('https://api.openweathermap.org/data/2.5/weather?q='+city+'&lang=tr&units=metric&appid=...');
final response = await http.get(url);
if (response.statusCode == 200) {
return WeatherModel.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to load post');
}
}
readJson() async {
var response = await rootBundle.loadString('lib/assets/cities.json');
Map<String, dynamic> map = await json.decode(response);
return map["cities"];
}
}
view raw services hosted with ❤ by GitHub

Bu dosyada ise Api'a istek atıyoruz. İstek attığımız url "https://api.openweathermap.org/data/2.5/weather?q='+city+'&lang=tr&units=metric&appid=..."

Url'in sonunda gördüğünüz "appid=..." kısmı sizin bu siteye girip kaydolduğunuzda aldığınız bir anahtarı koyacağınız kısım. Yani OpenWeather sistemine kaydolacaksınız, size bir app id verilecek, siz de istek url'inin sonuna "appid=" şeklinde koyacaksınız. Böylece api'a erişim sağlamış olacaksınız.

Servis dosyasında gördüğünüz readJson adındaki fonksiyon ile cities.json dosyasını okuyoruz. Json dosyasını okuduktan sonra geriye dönen cevabı bir map'e atıyoruz. Sonra map'in "cities" indeksli kısmını return ediyoruz.

Main.dart dosyamız şu şekilde;


import 'package:flutter/material.dart';
import 'package:weather_app/services/services.dart';
import 'models/models.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Color topColor=Colors.redAccent;
Color bottomColor= Colors.deepPurpleAccent;
ApiServices apiObj = new ApiServices();
late Future<WeatherModel> weatherInf;
Map<String, dynamic> map = new Map();
List<String> cityList=[];
String cityName="";
cityListSet()
async {
var tempList = await apiObj.readJson();
for(int i=0; i<tempList.length;i++)
{
cityList.add(tempList[i]["name"]);
}
setState(() {
});
}
getWeather(String city)
{
setState(() {
weatherInf = apiObj.makeList(city: city);
});
}
getIcon(String weatherStatus)
{
if(weatherStatus == "açık")
{
topColor=Colors.deepOrangeAccent;
bottomColor= Colors.yellowAccent;
return Container(
child: Text("☀️", style: TextStyle(fontSize: 50),),
);
}
else if(weatherStatus == "parçalı bulutlu" || weatherStatus == "parçalı az bulutlu" || weatherStatus == "az bulutlu")
{
topColor=Colors.blue;
bottomColor= Colors.lightBlueAccent;
return Container(
child: Text("☁️", style: TextStyle(fontSize: 50)),
);
}
else if(weatherStatus == "kapalı")
{
topColor=Colors.white38;
bottomColor= Colors.white10;
return Container(
child: Text("🌫️", style: TextStyle(fontSize: 50)),
);
}
else if(weatherStatus == "sisli")
{
topColor=Colors.white10;
bottomColor= Colors.brown;
return Container(
child: Text("🌁", style: TextStyle(fontSize: 50)),
);
}
else
{
return Container(
child: Text("❔", style: TextStyle(fontSize: 50)),
);
}
}
initState() {
cityListSet();
getWeather("edirne");
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.redAccent,
title: Text("WEATHER APP", style: TextStyle(
color: Colors.deepPurple,
fontSize: 30
),),
centerTitle: true,
toolbarHeight: 100,
),
body: SingleChildScrollView(
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height*0.85,
child: FutureBuilder<WeatherModel>(
future: weatherInf,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Container(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.fromLTRB(0, 20, 0, 0),
child: Text("🏙️ Şehir seçiniz:", style: TextStyle(fontSize: 30, color: Colors.black),),
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(width: 200, height: 30, color:Colors.white,margin: EdgeInsets.fromLTRB(0, 20, 0, 0),
child: Autocomplete<String>(
onSelected: (String option)
{
getWeather(cityName);
},
optionsBuilder: (TextEditingValue textEditingValue) {
cityName=textEditingValue.text;
if (textEditingValue.text == '') {
return const Iterable<String>.empty();
}
return cityList.where((String option) {
return option.contains(textEditingValue.text.toLowerCase());
});
},
),),
],
),
Container(
margin: EdgeInsets.fromLTRB(0, 50, 0, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container( margin: EdgeInsets.fromLTRB(0, 10, 0, 0),child: Text(snapshot.data?.city ?? "BOŞ", style: TextStyle(color: Colors.black, fontSize: 25),)),
getIcon(snapshot.data?.cityStatus ?? "BOŞ"),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(margin: EdgeInsets.fromLTRB(0, 5, 0, 0),child: Text(snapshot.data?.cityWeather.toString() ?? "0.0", style: TextStyle(color: Colors.black, fontSize: 50)))
],
)
],
),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [topColor, bottomColor])
),
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return Container(child: Center(child: Text("Bilgi geliyor...", style: TextStyle(fontSize: 24),)));
}
),
),
),
);
}
}

Modelimizi ve servisimizi import etmeyi unutmuyoruz;

import 'package:flutter/material.dart';
import 'package:weather_app/services/services.dart';

initState() {
cityListSet();
getWeather("edirne");
super.initState();
}


Uygulamamızın ilk yüklenişinde çalışan fonksiyonumuza cityListSet ve getWeather fonksiyonlarını yazdım. Sebebi, ekran çizilirken cities.json dosyasından şehirleri hemen çekip listeye atması ve uygulama ilk açıldığında istediğim şehri parametre olarak göndererek hava durumunu api'dan istemesidir.

getWeather(String city)
{
setState(() {
weatherInf = apiObj.makeList(city: city);
});
}

Bu fonksiyonumuzda ise servis dosyasından oluşturduğumuz nesne ile makeList fonksiyonuna ulaşıp istek atıyoruz. İstek url'inin içinde bulunan "city" değişkeninin içine buradan veri gönderiliyor.

cityListSet()
async {

var tempList = await apiObj.readJson();
for(int i=0; i<tempList.length;i++)
{
cityList.add(tempList[i]["name"]);
}

setState(() {

});
}

Bu fonksiyonumuzda AutoComplete widget'ının kullanacağı listenin içi cities.json dosyasının içindeki verilerle dolduruluyor. Bunu basit bir for döngüsü ile halledebilirsiniz.

Autocomplete<String>(
onSelected: (String option)
{
getWeather(cityName);
},
optionsBuilder: (TextEditingValue textEditingValue) {
cityName=textEditingValue.text;

if (textEditingValue.text == '') {
return const Iterable<String>.empty();
}
return cityList.where((String option) {

return option.contains(textEditingValue.text.toLowerCase());
});
},

)

Geriye daha fazla iş kalmıyor, ekran tasarımını yapıyoruz. Burada ekstra olan kısım Autocomplete widget'ı. Görüldüğü gibi onSelected aktif olduğunda getWeather fonksiyonu çağırılıyor. Çağırılırken cityName parametre olarak gönderiliyor. Cityname ise textEditingValue'nun aldığı değer, cityName değişkeninin içine atılırken bu değer küçük harflere çevriliyor. Çünkü api'daki şehir isimleri tamamen küçük harflerden oluşuyor.
Geriye kalan diğer kodlar ekranı süslemek için yazıldı, api'dan gelen açıklamaya göre çeşitli ikonlar ve renkler ekranı süsleyecek.
Uygulamanın tamamına github hesabımdan ulaşabilirsiniz. Github hesabım buradadır.

İşinize yarayacağını umuyorum ve iyi günler diliyorum.

Yorumlar

Bu blogdaki popüler yayınlar

DONANIMSAL BİLGİ (ANAKART)

VB.NET'TE VERİTABANI İŞLEMLERİ

VB.NET'TE VERİTABANINA KAYIT EKLEME İŞLEMİ