So I have this code that fetches routes from one place to another. Please see the picture attached below.
I need to add details for each journey which will be hidden unless you click on 'Details' button, I want to show the data in a ExpansionTile/ExpansionPanel - basically a collapsing element.
The problem is that when I use the setState() {...}
on the button, it will show the data indeed but it will also make the API call again.
The method getData()
gets triggered in the build widget which is why (I suppose) this is happening but I don't know how to solve this.
Is there a better way of doing it?
Any help/improvements will be highly appreciated as I am new to Flutter =)
...
class _PlanJourney extends State<PlanJourney> {
String data;
final from;
final to;
final type;
final time;
static var date = new DateTime.now();
final String formattedDate = new DateFormat('yyyy-MM-dd').format(date);
double _animatedHeight = 100.0;
Map<String,dynamic> journeyData;
_PlanJourney(this.from, this.to, this.type, this.time);
Future<String> getData() async {
http.Response response = await http.get(url);
data = response.body;
journeyData = json.decode(data);
debugPrint(journeyData.toString());
}
@override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
title: Text('Plan a journey'.toUpperCase(),
style: TextStyle(
color: Colors.black,
fontSize: 20,
fontWeight: FontWeight.bold
)
),
iconTheme: IconThemeData(
color: Color(0xFF0984e3),
),
backgroundColor: Colors.white,
),
resizeToAvoidBottomPadding: false,
body: SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(),
child: FutureBuilder(
future: getData(),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if(snapshot.connectionState == ConnectionState.done){
List<Widget> elements = new List<Widget>();
for(var i = 0; i < journeyData['routes'].length; i++){
List<Widget> iconList = new List<Widget>();
String duration;
String start = journeyData['routes'][i]['departure_time'];
String end;
String stress = '2 min';
for(var j = 0; j < journeyData['routes'][i]['route_parts'].length; j++){
if(journeyData['routes'][i]['route_parts'][j]['mode'] == 'foot'){
iconList.add(IconTheme(
data: IconThemeData(
color: Color(0xFFbfcdd5)
),
child: Icon(Icons.directions_walk),
)
);
} else if(journeyData['routes'][i]['route_parts'][j]['mode'] == 'tube'){
iconList.add(IconTheme(
data: IconThemeData(
color: Color(0xFFbfcdd5)
),
child: Icon(Icons.train),
)
);
} else if(journeyData['routes'][i]['route_parts'][j]['mode'] == 'bus'){
iconList.add(IconTheme(
data: IconThemeData(
color: Color(0xFFbfcdd5)
),
child: Icon(Icons.directions_bus),
)
);
}
duration = journeyData['routes'][i]['duration'];
end = journeyData['routes'][i]['arrival_time'];
}
elements.add(Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
alignment: Alignment.topLeft,
margin: EdgeInsets.only(left: 15, right: 15),
padding: EdgeInsets.all(10),
child: new Wrap(
direction: Axis.horizontal,
crossAxisAlignment: WrapCrossAlignment.start,
spacing: 5,
runSpacing: 5,
children: iconList
),
),
Container(
alignment: Alignment.topLeft,
margin: EdgeInsets.only(left: 15, right: 15),
padding: EdgeInsets.all(10),
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget> [
Column(
children: <Widget>[
Text('Duration',
style: TextStyle(
fontFamily: "Gotham Pro",
fontWeight: FontWeight.w300,
fontSize: 14
)
),
Padding(
padding: EdgeInsets.only(top: 5),
),
Text(duration)
],
),
Column(
children: <Widget>[
Text('Start',
style: TextStyle(
fontFamily: "Gotham Pro",
fontWeight: FontWeight.w300,
fontSize: 14
)
),
Padding(
padding: EdgeInsets.only(top: 5),
),
Text(start),
],
),
Column(
children: <Widget>[
Text('End',
style: TextStyle(
fontFamily: "Gotham Pro",
fontWeight: FontWeight.w300,
fontSize: 14
)
),
Padding(
padding: EdgeInsets.only(top: 5),
),
Text(end),
],
),
Column(
children: <Widget>[
Text('Stress',
style: TextStyle(
fontFamily: "Gotham Pro",
fontWeight: FontWeight.w300,
fontSize: 14
)
),
Padding(
padding: EdgeInsets.only(top: 5),
),
Text(stress)
],
)
]
),
),
Container(
alignment: Alignment.topLeft,
margin: EdgeInsets.only(left: 15, right: 15),
child: Row(
children: <Widget>[
OutlineButton(
child: Text('Details',
style: TextStyle(
color: Color(0xFF0c85e4),
fontFamily: "Gotham Pro",
fontWeight: FontWeight.w700
)
),
borderSide: BorderSide(
color: Color(0xFF0c85e4), //Color of the border
style: BorderStyle.solid, //Style of the border
width: 2, //width of the border
),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
onPressed: ()=>setState((){
_animatedHeight!=0.0 _animatedHeight=0.0:_animatedHeight=100.0;
}
),
),
Padding(
padding: EdgeInsets.only(left: 15, top: 15),
),
RaisedButton(
child: Text('Save',
style: TextStyle(
color: Colors.white,
fontFamily: "Gotham Pro",
fontWeight: FontWeight.w700,
)
),
color: Color(0xFF08b894),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
onPressed: (){},
)
],
)
),
AnimatedContainer(duration: const Duration(milliseconds: 120),
child: new Text("Journey data will go here"),
height: _animatedHeight,
color: Colors.tealAccent,
width: 200.0,
),
Divider()
],
),
));
}
return new Column(children: elements);
}else if(snapshot.connectionState == ConnectionState.waiting){
return Text("loading ...");
}
},
),
)
)
);
}
}