Last active
August 30, 2018 15:58
-
-
Save rmarau/baa31a9c4032de388a2b7777c8bae27e to your computer and use it in GitHub Desktop.
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 'package:flutter/material.dart'; | |
import 'package:http/http.dart'; | |
import 'package:html/parser.dart' show parse; | |
import 'package:html/dom.dart' as dom; | |
void main() => runApp(new MyApp()); | |
class MyApp extends StatelessWidget { | |
// This widget is the root of your application. | |
@override | |
Widget build(BuildContext context) { | |
return new MaterialApp( | |
title: 'Fun with Flags', | |
theme: new ThemeData( | |
primarySwatch: Colors.blue, | |
), | |
home: new MyHomePage(title: 'Fun with Flags'), | |
); | |
} | |
} | |
class MyHomePage extends StatefulWidget { | |
MyHomePage({Key key, this.title}) : super(key: key); | |
final String title; | |
@override | |
_MyHomePageState createState() => new _MyHomePageState(); | |
} | |
class _MyHomePageState extends State<MyHomePage> { | |
List<ListEntry> flags = List<ListEntry>(); | |
@override | |
void initState() { | |
_loadFlags(); | |
} | |
void _loadFlags(){ | |
get("https://en.wikipedia.org/wiki/Gallery_of_sovereign_state_flags") | |
.then((Response response){ | |
List<dom.Element> imgElems = parse(response.body) | |
.getElementsByClassName("thumbborder"); | |
flags.clear(); | |
imgElems.forEach((dom.Element elem){ | |
String name = elem.attributes['alt'] | |
.replaceAll( RegExp("Flag of (the)?"), "").trim(); | |
String url = elem.attributes['src'].toString(); | |
flags.add(ListEntry(name, url.startsWith("http") ? | |
url : "https:" + url)); | |
}); | |
setState(() { }); | |
}); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return new Scaffold( | |
appBar: new AppBar( | |
title: new Text(widget.title), | |
), | |
body: new ListView.builder( | |
itemCount: flags.length, | |
itemBuilder: (BuildContext ctx, int index) { | |
return ExpandableCard( | |
defaultSize: 100.0, | |
expandedSize: 150.0, | |
header: new ListTile( | |
key: new ObjectKey(flags[index].name), | |
leading: Container(width: 100.0, height: 100.0, | |
child: new Image.network(flags[index].url, fit: BoxFit.contain,), | |
), | |
title: new Text(flags[index].name), | |
), | |
body: TextField( | |
decoration: InputDecoration(labelText: "Focus this > Scroll far down > Expand any"), | |
), | |
isExpanded: flags[index].isExpanded, | |
onTap: (){ | |
flags[index].isExpanded = !flags[index].isExpanded; | |
//Tried to release the focus before expanding. No luck! | |
//FocusScope.of(context).requestFocus(new FocusNode()); | |
setState(() { | |
/*flags = new List.from(flags);*/ | |
}); | |
}, | |
); | |
} | |
), | |
floatingActionButton: new FloatingActionButton( | |
onPressed: _loadFlags, | |
tooltip: 'Reload', | |
child: new Icon(Icons.refresh), | |
), | |
); | |
} | |
} | |
class ListEntry{ | |
final String name; | |
final String url; | |
bool isExpanded; | |
ListEntry(this.name, this.url, {this.isExpanded=false}); | |
} | |
class ExpandableCard extends StatelessWidget { | |
final double defaultSize; | |
final double expandedSize; | |
final Widget header; | |
final Widget body; | |
final bool isExpanded; | |
final VoidCallback onTap; | |
ExpandableCard({ @required this.defaultSize, @required this.expandedSize, | |
@required this.header , @required this.body, this.isExpanded=false, this.onTap}); | |
@override | |
Widget build(BuildContext context) { | |
return | |
new GestureDetector( | |
behavior: HitTestBehavior.opaque, | |
onTap: onTap, | |
child: new SafeArea( | |
top: false, | |
bottom: false, | |
child: new AnimatedContainer( | |
padding: const EdgeInsets.symmetric(horizontal: 4.0), | |
curve: Curves.fastOutSlowIn, | |
duration: kThemeAnimationDuration, | |
height: isExpanded ? expandedSize : defaultSize, | |
child: | |
new Card( | |
elevation: 1.0, | |
color: Colors.white, | |
child: | |
new Padding( | |
padding: new EdgeInsets.all(10.0), | |
child: new Column( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
mainAxisSize: MainAxisSize.max, | |
children: <Widget>[ | |
header, | |
new AnimatedCrossFade( | |
firstChild: new Container(height: 0.0), | |
secondChild: body, | |
firstCurve: const Interval(0.0, 0.6, curve: Curves.fastOutSlowIn), | |
secondCurve: const Interval(0.4, 1.0, curve: Curves.fastOutSlowIn), | |
sizeCurve: Curves.fastOutSlowIn, | |
crossFadeState: isExpanded ? CrossFadeState.showSecond : CrossFadeState.showFirst, | |
duration: kThemeAnimationDuration, | |
), | |
], | |
), | |
), | |
), | |
) | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment