Sobatcoding.com - Membuat aplikasi mobile info cuaca menggunakan data BMKG dengan Flutter
Artikel kali ini kita akan coba membuat sebuah aplikasi mobile info cuaca menggunakan data terbuka dari BMKG. Data BMKG ini bersifat open source dan format XML bisa kalian cek di link berikut https://data.bmkg.go.id/prakiraan-cuaca/.
Contoh data yang kita gunakan kali ini adalah hanya kota Jawa Timur saja. Untuk link source data xmlnya adalah berikut ini
https://data.bmkg.go.id/DataMKG/MEWS/DigitalForecast/DigitalForecast-JawaTimur.xml
Buatlah sebuah project flutter baru, contoh flutter cuaca. Tambahkan beberapa dependencies berikut
xml: ^6.1.0
http: ^0.13.5
xml2json: ^5.3.5
weather_icons: ^3.0.0
Buatlah sebuah function untuk fetch data XML dari BMKG
Future<List<dynamic>> fetchDataBMKGJatim() async {
var uRL =
"https://data.bmkg.go.id/DataMKG/MEWS/DigitalForecast/DigitalForecast-JawaTimur.xml";
final result = await http.get(Uri.parse(uRL));
final Xml2Json xml2Json = Xml2Json();
xml2Json.parse(result.body);
var json = xml2Json.toGData();
Map<String, dynamic> map = jsonDecode(json);
return map['data']['forecast']['area'];
}
Tampilkan data XML di atas ke dalam listview menggunakan stream builder seperti berikut
Expanded(
child: FutureBuilder<List<dynamic>>(
future: fetchDataBMKGJatim(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
return Text("${snapshot.error}");
}
if (snapshot.hasData) {
List<dynamic> dataKota = snapshot.data;
}
return ListView.builder(
padding: const EdgeInsets.all(10),
itemCount: dataKota.length,
itemBuilder: (BuildContext context, int index) {
var item = dataKota[index];
return buildListKota(item);
});
} else {
return const Center(child: CircularProgressIndicator());
}
},
),
)
Buatlah widget untuk menampilkan detail info cuaca
Map<String, dynamic>? dataHumadity;
Map<String, dynamic>? windDirection;
Map<String, dynamic>? windSpeed;
Map<String, dynamic>? dataTemperature;
Map<String, dynamic>? dataWeather;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
widget.title,
style: const TextStyle(fontSize: 18),
),
centerTitle: true,
),
body: Container(
color: Colors.lightBlue,
padding: const EdgeInsets.all(10),
child: Column(
children: [
const SizedBox(
height: 10,
),
Padding(
padding: const EdgeInsets.all(13.0),
child: TextField(
controller: searchController,
onChanged: (value) {
setState(() {
textSearch = value;
});
},
decoration: const InputDecoration(
labelText: 'Cari disini ...',
suffixIcon: Icon(Icons.search),
fillColor: Colors.white,
filled: true,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(width: 2, color: Colors.white10),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(width: 2, color: Colors.white38),
)),
),
),
Container(
height: 20,
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(width: 0.8, color: Colors.white),
),
),
),
Expanded(
child: FutureBuilder<List<dynamic>>(
future: fetchDataBMKGJatim(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
return Text("${snapshot.error}");
}
if (snapshot.hasData) {
List<dynamic> dataKota = snapshot.data;
if (textSearch.isNotEmpty) {
dataKota = dataKota.where((element) {
return element['description']
.toString()
.toLowerCase()
.contains(textSearch.toString().toLowerCase());
}).toList();
}
return ListView.builder(
padding: const EdgeInsets.all(10),
itemCount: dataKota.length,
itemBuilder: (BuildContext context, int index) {
var item = dataKota[index];
return buildListKota(item);
});
} else {
return const Center(child: CircularProgressIndicator());
}
},
),
),
],
),
));
}
}
Sebagai tambahan kita akan mencoba menambahkan filter ke dalam stream builder yang telah kita buat. Caranya adalah seperti berikut
Buatlah sebuah widget TextField sebagai input pencarian
Padding(
padding: const EdgeInsets.all(13.0),
child: TextField(
controller: searchController,
onChanged: (value) {
setState(() {
textSearch = value;
});
},
decoration: const InputDecoration(
labelText: 'Cari disini ...',
suffixIcon: Icon(Icons.search),
fillColor: Colors.white,
filled: true,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(width: 2, color: Colors.white10),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(width: 2, color: Colors.white38),
)),
),
)
Kemudian tambahkan function untuk memproses filter data dari stream builder
if (snapshot.hasData) {
List<dynamic> dataKota = snapshot.data;
if (textSearch.isNotEmpty) {
dataKota = dataKota.where((element) {
return element['description']
.toString()
.toLowerCase()
.contains(textSearch.toString().toLowerCase());
}).toList();
}
kode di atas berfungsi untuk mencari index description berdasarkan pencarian yang kita masukkan di widget TextField.
Tambahkan kode di atas di dalam widget stream builder sehingga menjadi seperti berikut
Expanded(
child: FutureBuilder<List<dynamic>>(
future: fetchDataBMKGJatim(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
return Text("${snapshot.error}");
}
if (snapshot.hasData) {
List<dynamic> dataKota = snapshot.data;
if (textSearch.isNotEmpty) {
dataKota = dataKota.where((element) {
return element['description']
.toString()
.toLowerCase()
.contains(textSearch.toString().toLowerCase());
}).toList();
}
return ListView.builder(
padding: const EdgeInsets.all(10),
itemCount: dataKota.length,
itemBuilder: (BuildContext context, int index) {
var item = dataKota[index];
return buildListKota(item);
});
} else {
return const Center(child: CircularProgressIndicator());
}
},
),
)
Hasil akhir kode di atas kurang lebih seperti berikut
Untuk source lengkap kalian bisa cek di link berikut https://github.com/sobatcoding21/cuaca.
Kalian juga bisa custom sesuai dengan kreatifitas kalian
Sekian tutorial kali ini. Jika teman-teman memiliki pertanyaan atau saran mengenai artikel ini, jangan ragu untuk meninggalkan komentar pada form di bawah ini.
Semoga bermanfaat.
Komentar 0