MAKING YOUR FIRST WEATHER APP IN FLUTTER,USING OPENWEATHERMAP API.
API simply means application programming interface, an API is a messenger that takes request and tells your system what to do and sends a response back to you. There are different types of APIs e.g. weather APIs, ecommerce APIs just to mention a few. In this tutorial we will focus on a public API, a public API is an API that can be used for free.
In this case we will use an API from openweathermap.org, Openweathermap provides different weather APIs but our focus will be the CURRENT WEATHER DATA API. Visit the URL and create a free account, go on CURRENT WEATHER DATA and hit the subscribe button after that It will take you to Current weather and forecasts collection and when there go to the first card free version and hit the button Get API key. You will get something like this as your API key 717d16ccc2decxxxxxxxxxx5ad73a17x which you will use to send requests, you can find it in your emails or you can simply go to your account created on openweathermap and click on API keys and you're going to see the same API key you received in the email. To call an API you will need to copy the following link in your browser api.openweathermap.org/data/2.5/weather?q=L..{API key} replace the {API key} in the URL with your API key without the brackets and paste it in your browser and you will get something like this below;
{ "coord": { "lon": -0.13, "lat": 51.51 }, "weather": [ { "id": 300, "main": "Drizzle", "description": "light intensity drizzle", "icon": "09d" } ], "base": "stations", "main": { "temp": 280.32, "pressure": 1012, "humidity": 81, "temp_min": 279.15, "temp_max": 281.15 }, "visibility": 10000, "wind": { "speed": 4.1, "deg": 80 }, "clouds": { "all": 90 }, "dt": 1485789600, "sys": { "type": 1, "id": 5091, "message": 0.0103, "country": "GB", "sunrise": 1485762037, "sunset": 1485794875 }, "id": 2643743, "name": "London", "cod": 200 }
This document is in json format so copy it, go to the following jsonformatter.curiousconcept.com/# once there paste it on the tub to get the clear format of the document.
3. We are going to have a simple UI that we are going to use to display the weather data collected from the API. We are going to make at least three (5) files; [main.dart ]
[shared.dart ]
[database_helper.dart ]
[weatherdetails.dart ]
[searchweather.dart]
In the main.dart we are going to have the following code;
import 'package:flutter/material.dart';
import 'weatherdetails.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home:HomeForClipPath1(),
);
}
}
In the weatherdetails.dart we are going to have the following code;
Before anything go pub.dev and get the following dependencies and add them to the pubspec.yaml and add them under the dependencies below the cupertino_icons
And import the http: and font_awesome_flutter in your weatherdetails.dart.
For the font_awesome_flutter icons to work you have to uninstall and reinstall the app.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'shared.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'database_helper.dart';
import 'searchweather.dart';
class HomeForClipPath1 extends StatefulWidget {
final dynamic city;
const HomeForClipPath1({Key key,this.city}) : super(key: key);
@override
_HomeForClipPath1State createState() => _HomeForClipPath1State();
}
class _HomeForClipPath1State extends State<HomeForClipPath1> {
// setting dataBaseHelper object
DataBaseHelper dataBaseHelper = DataBaseHelper();
@override
Widget build(BuildContext context) {
final double width = MediaQuery.of(context).size.width;
final double height = MediaQuery.of(context).size.height;
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: FutureBuilder(
future: dataBaseHelper.fetchData(city: widget.city ?? 'lusaka'),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.hasData) {
return Column(
children: <Widget>[
ClipPath(
clipper: ClipHere(),
child: Container(
width: width,
height: height * 0.50,
decoration: BoxDecoration(
color: Colors.green[900],
),
child: Center(
//children of the cliped
child: Column(
children: [
SizedBox(
height: 30.0,
),
//next
Text(
'current weather',
style: fonts,
),
//next
Text(
"${snapshot.data['main']['temp']}°",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.normal,
fontStyle: FontStyle.italic,
fontSize: 68,
),
),
//next
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.location_on),
Text(
snapshot.data['name'].toString(),
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.normal,
fontStyle: FontStyle.italic,
fontSize: 15,
),
),
],
),
],
),
),
),
),
//next to show weather
ListTile(
leading: CircleAvatar(
child: FaIcon(FontAwesomeIcons.thermometerHalf,
color: Colors.black, size: 20.0),
radius: 25.0,
backgroundColor: Colors.green[800],
),
title: Text('Temperature'),
trailing: Text(
"${snapshot.data['main']['temp']}°",
),
),
//next
ListTile(
leading: CircleAvatar(
child: FaIcon(FontAwesomeIcons.airbnb,
color: Colors.black, size: 20.0),
radius: 25.0,
backgroundColor: Colors.green[800],
),
title: Text('Humidity'),
trailing: Text("${snapshot.data['main']['humidity']}%"),
),
//next
ListTile(
leading: CircleAvatar(
child: FaIcon(FontAwesomeIcons.wind,
color: Colors.black, size: 20.0),
radius: 25.0,
backgroundColor: Colors.green[800],
),
title: Text('Wind Speed'),
trailing: Text("${snapshot.data['wind']['speed']}m/s"),
),
//next
ListTile(
leading: CircleAvatar(
child: FaIcon(FontAwesomeIcons.skyatlas,
color: Colors.black, size: 20.0),
radius: 25.0,
backgroundColor: Colors.green[800],
),
title: Text('Pressure'),
trailing: Text("${snapshot.data['main']['pressure']}mb"),
),
//BottomBar
ClipPath(
clipper: BottomClip(),
child: Container(
color: Colors.green[900],
width: width,
height: height * 0.15,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(
height: 50,
),
Text(
'max: ${snapshot.data['main']['temp_max']}°'),
Text(
'min : ${snapshot.data['main']['temp_min']}°'),
],
),
SizedBox(
width: 150,
),
Container(
alignment: Alignment.bottomRight,
child: FlatButton.icon(
onPressed: () => Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => SearchData(),
),
),
icon: Icon(
Icons.search,
size: 40,
),
label: Text(''),
),
),
],
),
),
),
],
);
} else {
return Center(child: CupertinoActivityIndicator());
}
}),
),
);
}
}
Shared.dart
This were we are going to put all our designs and this were we have to import the google_fonts .
In the shared.dart we are going to have the following code;
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class ClipHere extends CustomClipper<Path> {
@override
Path getClip(Size size) {
var path = Path();
path.lineTo(0, size.height - 75);
var controllPoint = Offset(size.width, size.height / 2);
var endPoint = Offset(size.width, size.height);
path.quadraticBezierTo(
controllPoint.dx, controllPoint.dy, endPoint.dx, endPoint.dy);
path.lineTo(size.width, size.height);
path.lineTo(size.width, 0);
return path;
}
@override
bool shouldReclip(CustomClipper oldClipper) => true;
}
class BottomClip extends CustomClipper<Path> {
@override
Path getClip(Size size) {
var path = Path();
path.lineTo(0, size.height - 95);
var controlPath = Offset(size.width / 2, size.height);
var endPath = Offset(size.width, size.height / 6);
path.quadraticBezierTo(
controlPath.dx, controlPath.dy, endPath.dx, endPath.dy);
path.lineTo(size.width, size.height);
path.lineTo(0, size.height);
return path;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) => true;
}
const textInputDecorations = InputDecoration(
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
width: 2.0,
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.green,
width: 2.0,
),
),
);
var fonts = GoogleFonts.amaticSc(
fontWeight: FontWeight.bold,
fontSize: 30.0,
fontStyle: FontStyle.italic,
);
in the searchwather.dart , this is where we are going to put the textformfield the one we are going to use for typing the city name.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'shared.dart';
import 'weatherdetails.dart';
import 'database_helper.dart';
class SearchData extends StatefulWidget {
@override
_SearchDataState createState() => _SearchDataState();
}
class _SearchDataState extends State<SearchData> {
TextEditingController _userCityName = TextEditingController();
DataBaseHelper dataBaseHelper = DataBaseHelper();
@override
Widget build(BuildContext context) {
final double width = MediaQuery.of(context).size.width;
// final double height = MediaQuery.of(context).size.height;
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Colors.green[900],
body: Column(
children: <Widget>[
Container(
width: width,
//height: height,
color: Colors.green[900],
child: Column(
children: <Widget>[
SizedBox(
height: 50,
),
Text(
'check your weather',
style: fonts,
),
SizedBox(
height: 50,
),
Form(
child: Column(
children: <Widget>[
TextFormField(
controller: _userCityName,
decoration: textInputDecorations.copyWith(
hintText: 'search city',
),
),
//searchButton
SizedBox(
height: 30,
),
RaisedButton(
child: Text('search'),
onPressed: () async {
// close the keyboard before user navigate to diffrent screen
FocusScope.of(context).requestFocus(FocusNode());
Navigator.of(context)
.pushReplacement(CupertinoPageRoute(
builder: (context) => HomeForClipPath1(
city: _userCityName.text
.toString()
.toLowerCase(),
),
),
);
},
),
],
),
),
],
),
),
],
),
),
);
}
}
database_helper.dart this is where we are going to put the code that fetches our API
import 'dart:convert' show json;
import 'package:http/http.dart' as http;
//class to hold our Database Functions
class DataBaseHelper {
Future fetchData({String city}) async {
String api = 'http://api.openweathermap.org/data/2.5/weather';
String appId = "YOUR_API_KEY";
String url = '$api?q=$city&units=metric&APPID=$appId';
http.Response response = await http.get(url);
var results = json.decode(response.body);
return results;
}
}