Building a Vibrant Weather App with Flutter and Integrating Native Splash Screen
Introduction
In this tutorial, we will build a weather app using Flutter. The app will feature a vibrant user interface, a native splash screen, and the ability to fetch weather data based on the user's location or a searched city name.
Project Setup
1. Create a New Flutter Project
First, create a new Flutter project:
flutter create weather_app
cd weather_app2. Add Dependencies
Update your pubspec.yaml file to include the necessary dependencies:
dependencies:
flutter:
sdk: flutter
animations: ^2.0.5
flutter_blurhash: ^0.7.0
flutter_svg: ^2.0.10
geolocator: ^8.0.0
http: ^0.13.4
dev_dependencies:
flutter_native_splash: ^2.0.5
Run the following command to install the packages:
flutter pub get
3. Configure Flutter Native Splash
Add the following configuration to your pubspec.yaml file for the native splash screen:
flutter_native_splash:
color: "#42a5f5"
image: assets/splash.png
android: true
ios: true
web: false
android_gravity: fill
ios_content_mode: scaleAspectFill
4. Add Splash Screen Image
Place your splash screen image in the assets directory. Ensure your pubspec.yaml includes the assets section:
flutter:
assets:
- assets/splash.png
Run the following command to generate the splash screen configuration:
flutter pub run flutter_native_splash:create
Building the Weather App
1. Weather Service
Create a weather_service.dart file in a services directory to fetch weather data from OpenWeatherMap:
import 'dart:convert';import 'package:http/http.dart' as http;
class WeatherService { static const String apiKey = '35e48f639d31fb3f53ac30e814bb6bb5'; static const String apiUrl = 'https://api.openweathermap.org/data/2.5/weather';
Future<Map<String, dynamic>> getWeather(double lat, double lon) async { final response = await http.get( Uri.parse( "https://api.openweathermap.org/data/2.5/weather?lat=$lat&lon=$lon&units=metric&appid=$apiKey"), );
if (response.statusCode == 200) { return json.decode(response.body); } else { throw Exception('Failed to load weather data'); } }
Future<Map<String, dynamic>> getWeatherByCity(String cityName) async { final response = await http .get(Uri.parse('$apiUrl?q=$cityName&units=metric&appid=$apiKey'));
if (response.statusCode == 200) { return json.decode(response.body); } else { throw Exception('Failed to load weather data'); } }}
2. Home Screen
Create home_screen.dart in the screens directory and update it as follows:
import 'package:animations/animations.dart';import 'package:flutter/material.dart';import 'package:flutter_blurhash/flutter_blurhash.dart';import 'package:flutter_svg/flutter_svg.dart';import 'package:geolocator/geolocator.dart';import '../Services/weather_service.dart';
class HomeScreen extends StatefulWidget { @override _HomeScreenState createState() => _HomeScreenState();}
class _HomeScreenState extends State<HomeScreen> { WeatherService _weatherService = WeatherService(); String _temperature = ''; String _description = ''; String _icon = ''; bool _loading = true; final TextEditingController _searchController = TextEditingController();
@override void initState() { super.initState(); _fetchWeather(); }
Future<void> _fetchWeather({String? cityName}) async { try { var weatherData; if (cityName != null && cityName.isNotEmpty) { weatherData = await _weatherService.getWeatherByCity(cityName); } else { Position position = await _getCurrentLocation(); weatherData = await _weatherService.getWeather( position.latitude, position.longitude); } setState(() { _temperature = '${weatherData['main']['temp']}°C'; _description = weatherData['weather'][0]['description']; _icon = getWeatherIcon(weatherData['weather'][0]['main']); _loading = false; }); } catch (e) { print('Error fetching weather: $e'); setState(() { _loading = false; }); } }
Future<Position> _getCurrentLocation() async { bool serviceEnabled = await Geolocator.isLocationServiceEnabled(); if (!serviceEnabled) { return Future.error('Location services are disabled.'); }
LocationPermission permission = await Geolocator.checkPermission(); if (permission == LocationPermission.denied) { permission = await Geolocator.requestPermission(); if (permission == LocationPermission.denied) { return Future.error('Location permissions are denied'); } }
if (permission == LocationPermission.deniedForever) { return Future.error( 'Location permissions are permanently denied, we cannot request permissions.'); }
return await Geolocator.getCurrentPosition(); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Weather App'), actions: [ IconButton( icon: const Icon(Icons.search), onPressed: () { showSearchDialog(context); }, ), ], ), body: _loading ? const Center(child: CircularProgressIndicator()) : PageTransitionSwitcher( duration: const Duration(milliseconds: 300), transitionBuilder: (child, animation, secondaryAnimation) => SharedAxisTransition( child: child, animation: animation, secondaryAnimation: secondaryAnimation, transitionType: SharedAxisTransitionType.horizontal, ), child: Column( key: const ValueKey<int>(0), children: [ Expanded( child: Stack( children: [ const BlurHash( hash: 'LEHV6nWB2yk8pyo0adR*.7kCMdnj', imageFit: BoxFit.cover, ), Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ SvgPicture.asset( _icon, height: 150, ), const SizedBox(height: 20), Text( _temperature, style: const TextStyle( fontSize: 50, fontWeight: FontWeight.bold, color: Colors.blue, ), ), Text( _description, style: const TextStyle( fontSize: 30, color: Colors.amber, ), ), ], ), ), ], ), ), ], ), ), ); }
void showSearchDialog(BuildContext context) { showDialog( context: context, builder: (context) { return AlertDialog( title: const Text('Search City'), content: TextField( controller: _searchController, decoration: const InputDecoration(hintText: 'Enter city name'), ), actions: [ TextButton( child: const Text('Cancel'), onPressed: () { Navigator.of(context).pop(); }, ), TextButton( child: const Text('Search'), onPressed: () { Navigator.of(context).pop(); _fetchWeather(cityName: _searchController.text); }, ), ], ); }, ); }}
String getWeatherIcon(String condition) { switch (condition) { case 'Clear': return 'lib/assets/sunny-day.svg'; case 'Clouds': return 'lib/assets/cloud-view.svg'; case 'Rain': return 'lib/assets/icon-rain.svg'; case 'Drizzle': return 'lib/assets/rainbow.svg'; case 'Thunderstorm': return 'lib/assets/reshot-icon-weather-YRQ52EZUTW.svg'; case 'Snow': return 'lib/assets/snowflake.svg'; case 'Mist': case 'Smoke': case 'Haze': case 'Dust': case 'Fog': case 'Sand': case 'Ash': case 'Squall': case 'Tornado': return 'lib/assets/sunny-and-windy.svg'; default: return 'lib/assets/weather.svg'; }}
3. Ensure Assets are Included in pubspec.yaml
Ensure all your SVG files are included in the pubspec.yaml file:
flutter:
assets:
- lib/assets/cloud-view.svg
- lib/assets/hot-weather.svg
- lib/assets/icon-rain.svg
- lib/assets/rainbow.svg
- lib/assets/reshot-icon-weather-YRQ52EZUTW.svg
- lib/assets/snowflake.svg
- lib/assets/sunny-and-windy.svg
- lib/assets/sunny-day.svg
- lib/assets/sunset.svg
- lib/assets/weather.svg
4. Main Dart File
Ensure your main.dart file initializes the app correctly:
import 'package:flutter/material.dart';
Link to Repository:WeatherApp


Comments
Post a Comment