Created
May 18, 2018 16:15
-
-
Save xsokev/d5839a0e93439c7c84a2406f54f67dab to your computer and use it in GitHub Desktop.
Flutter Weather Screen Design with Current Temperature and Forecast
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:convert'; | |
import 'package:intl/intl.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:fluids/plugins/weather/models/models.dart'; //custom data models | |
import 'package:fluids/utils/md_icons.dart'; //material design community icons | |
class CityForecast extends StatelessWidget { | |
final GlobalKey<AnimatedListState> _listKey = GlobalKey<AnimatedListState>(); | |
final String city; | |
final String state; | |
final Forecast forecast; | |
CityForecast({this.city, this.state, this.forecast}); | |
@override | |
Widget build(BuildContext context) { | |
final int contentHgt = 240; | |
double imageHeight = MediaQuery.of(context).size.height - contentHgt; | |
return Stack( | |
children: <Widget>[ | |
new Positioned( | |
child: Image.network( | |
weatherImage, | |
fit: BoxFit.cover, | |
), | |
height: imageHeight, | |
top: 0.0, | |
left: 0.0, | |
right: 0.0, | |
), | |
new Scaffold( | |
appBar: new AppBar( | |
backgroundColor: Colors.transparent, | |
elevation: 0.0, | |
), | |
backgroundColor: Colors.transparent, | |
body: new Column( | |
mainAxisAlignment: MainAxisAlignment.end, | |
children: <Widget>[ | |
_makeWeatherRow(context), | |
Container( | |
height: contentHgt.toDouble(), | |
color: Colors.white, | |
child: new SafeArea( | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.start, | |
children: <Widget>[ | |
_makeWeatherExtra(context), | |
Expanded( | |
child: AnimatedList( | |
key: _listKey, | |
initialItemCount: forecast.daily.length, | |
scrollDirection: Axis.horizontal, | |
itemBuilder: (BuildContext context, int index, animation){ | |
return _makeDay(context, animation, forecast.daily[index]); | |
}, | |
), | |
) | |
], | |
), | |
), | |
) | |
], | |
), | |
), | |
], | |
); | |
} | |
_makeDay(BuildContext context, animation, Weather w){ | |
return FadeTransition( | |
opacity: animation, | |
child: SizeTransition( | |
sizeFactor: animation, | |
child: new Container( | |
width: 120.0, | |
decoration: BoxDecoration( | |
border: Border(right: BorderSide(width: 1.0, color: Colors.black26)), | |
), | |
margin: EdgeInsets.symmetric(vertical: 10.0), | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: <Widget>[ | |
Text(DateFormat('EEE').format(w.dateTime).toUpperCase()), | |
Expanded( | |
child: Icon(w.mcIcon, size: 40.0,), | |
), | |
Text('${w.temperatureMax.round()} / ${w.temperatureMin.round()}', style: Theme.of(context).textTheme.title,), | |
], | |
), | |
), | |
), | |
); | |
} | |
_makeWeatherRow(context) { | |
Weather current = forecast != null && forecast.currently != null ? forecast.currently : null; | |
return current == null ? Container() : Container( | |
color: Colors.black45, | |
padding: EdgeInsets.all(20.0), | |
child: new Column( | |
children: <Widget>[ | |
new Row( | |
crossAxisAlignment: CrossAxisAlignment.center, | |
children: <Widget>[ | |
Row( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: <Widget>[ | |
Text(current.temperature.toStringAsFixed(0), style: Theme.of(context).textTheme.display2.copyWith(color: Colors.white),), | |
Icon(MDIcons.temperature_fahrenheit, color: Colors.white, size: 30.0,), | |
], | |
), | |
new Expanded( | |
child: Container( | |
alignment: Alignment.center, | |
padding: const EdgeInsets.only(right: 30.0), | |
child: Icon(current.mcIcon, color: Colors.white, size: 60.0,), | |
), | |
), | |
Column( | |
crossAxisAlignment: CrossAxisAlignment.end, | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: <Widget>[ | |
Text('$city, $state'.toUpperCase(), style: Theme.of(context).textTheme.title.copyWith(color: Colors.white),), | |
Text(DateFormat('EEEEE, MMMM d').format(DateTime.now()).toUpperCase(), style: Theme.of(context).textTheme.body1.copyWith(color: Colors.white),), | |
], | |
) | |
], | |
), | |
_makeWeatherSummary(context), | |
], | |
), | |
); | |
} | |
_makeWeatherExtra(BuildContext context) { | |
Weather current = forecast != null && forecast.currently != null ? forecast.currently : null; | |
return current == null ? Container() : Container( | |
child: Column( | |
children: <Widget>[ | |
Container( | |
padding: const EdgeInsets.all(15.0), | |
child: Row( | |
mainAxisAlignment: MainAxisAlignment.spaceEvenly, | |
children: <Widget>[ | |
_makeExtraInfoStat(context, MDIcons.flag_variant_outline, '${current.windSpeed.round()} MPH'), | |
_makeExtraInfoStat(context, MDIcons.compass_outline, '${current.windDirection}'), | |
_makeExtraInfoStat(context, MDIcons.umbrella_outline, '${current.precipitationProbability.round()}%'), | |
], | |
), | |
), | |
Divider(), | |
], | |
), | |
); | |
} | |
_makeExtraInfoStat(BuildContext context, IconData icon, String info){ | |
return Row( | |
children: <Widget>[ | |
Icon(icon), | |
Text(info.toUpperCase(), style: Theme.of(context).textTheme.title,), | |
], | |
); | |
} | |
_makeWeatherSummary(BuildContext context) { | |
String summary = Utf8Codec().decode(forecast.dailySummary.codeUnits); | |
return Container( | |
child: Column( | |
children: <Widget>[ | |
Container( | |
padding: const EdgeInsets.only(top: 10.0), | |
child: Text( | |
summary, | |
style: Theme.of(context).textTheme.body1.copyWith(color: Colors.white), | |
), | |
), | |
], | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment