Flutter Widget 101 Part 4 (Navigation and Drawers)
1. Drawer
Official Doc- Material Design has 2 mode of navigation, Tabs or/and Drawer.
- Drawer slide in horizontally
- Use ListView (Scrollable) or Column as Child
- ListTitle for each single row
Details of User can be displayed with DrawerHeader, UserAccountsDrawerHeader
- onTap Behaviour can be set
- Wrapper: Material App > Scaffold > Drawer > ListView
Drawer: When tapped on row, will change Text in Main Page
void main(){ runApp(new MaterialApp(home: new DrawerTemp()),); } class DrawerTemp extends StatefulWidget { @override _DrawerTempState createState() => _DrawerTempState(); } class _DrawerTempState extends State<DrawerTemp> { String TextValue = "Original"; @override Widget build(BuildContext context) { return Scaffold( appBar: new AppBar( title: new Text("Drawer Test"), backgroundColor: Colors.lightBlueAccent, ), drawer: new Drawer( child: new ListView( children: <Widget>[ new UserAccountsDrawerHeader( accountName: new Text ("User Name"), accountEmail: new Text("Mickey@gmail.com"), decoration: new BoxDecoration(color: Colors.red), currentAccountPicture: new CircleAvatar(child: new Icon(Icons.local_library)), otherAccountsPictures: <Widget>[ new CircleAvatar(child: new Icon(Icons.accessibility),), new CircleAvatar(child: new Icon(Icons.account_circle),), ], ), new ListTile( trailing: new Icon(Icons.add_a_photo), title: new Text("At a Shopping Mall"), subtitle: new Text("Buying Food"), onTap: (){ setState(() {TextValue = "I am lazy, Hello World";}); Navigator.pop(context); }, ), ], ), ), body: new Center(child: new Text(TextValue),), ); } }
2.Navigation
Navigation.push(): add a route to navigator
Sample:
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => MyPage()));
returns Future
Navigation.pop(): return to previous page and remove route from navigator
bool pop <T extends Object>( BuildContext context, [T result])
Pop the top-most route off the navigator that most tightly encloses the given context.
Route: have to be created or use MaterialPageRoute with platform specific animation
main.dart
import 'package:flutter/material.dart'; import 'page1.dart'; import 'page2.dart'; void main(){ runApp(new MaterialApp(home: new DrawerTemp()),); } class DrawerTemp extends StatefulWidget { @override _DrawerTempState createState() => _DrawerTempState(); } class _DrawerTempState extends State<DrawerTemp> { String TextValue = "Original"; @override Widget build(BuildContext context) { return Scaffold( appBar: new AppBar( title: new Text("Drawer Test"), backgroundColor: Colors.lightBlueAccent, ), drawer: new Drawer( child: new ListView( children: <Widget>[ new UserAccountsDrawerHeader( accountName: new Text ("User Name"), accountEmail: new Text("Mickey@gmail.com"), decoration: new BoxDecoration(color: Colors.red), currentAccountPicture: new CircleAvatar(child: new Icon(Icons.local_library)), otherAccountsPictures: <Widget>[ new CircleAvatar(child: new Icon(Icons.accessibility),), new CircleAvatar(child: new Icon(Icons.account_circle),), ], ), new ListTile( trailing: new Icon(Icons.add_a_photo), title: new Text("At a Shopping Mall"), subtitle: new Text("Buying Food"), onTap: (){ setState(() {TextValue = "I am lazy, Hello World";}); Navigator.pop(context); }, ), new ListTile( trailing: new Icon(Icons.arrow_forward_ios), title: new Text("Go Page 1"), subtitle: new Text("Shopping Cart"), onTap: (){ Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context1)=>new page1("Page 1"))); }, ), new ListTile( trailing: new Icon(Icons.arrow_forward_ios), title: new Text("Go Page 2"), subtitle: new Text("Shopping Cart2"), onTap: (){ Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context2)=>new page2("Page 2"))); }, ), ], ), ), body: new Center(child: new Text(TextValue),), ); } }Page1import 'package:flutter/material.dart'; import 'page2.dart'; class page1 extends StatelessWidget { final String mtext; page1(this.mtext); @override Widget build(BuildContext context) { return Scaffold( appBar: new AppBar(title: new Text("Page 1"),backgroundColor: Colors.red,), body: new Center( child: new Column( children: <Widget>[ new Text("Welcome to Page 1"), new RaisedButton(onPressed: () { Navigator.pop(context); }, child:new Text("Back to Home"),), new RaisedButton(onPressed: () { Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context1)=>new page2("Page 2"))); }, child:new Text("To Shopping Cart 2"),), ], ), ), ); } }
Page2
import 'package:flutter/material.dart'; import 'page2.dart'; class page1 extends StatelessWidget { final String mtext; page1(this.mtext); @override Widget build(BuildContext context) { return Scaffold( appBar: new AppBar(title: new Text("Page 1"),backgroundColor: Colors.red,), body: new Center( child: new Column( children: <Widget>[ new Text("Welcome to Page 1"), new RaisedButton(onPressed: () { Navigator.pop(context); }, child:new Text("Back to Home"),), new RaisedButton(onPressed: () { Navigator.of(context).push(new NoAnimationMaterialPageRoute(builder: (BuildContext context1)=>new page2("Page 2"))); }, child:new Text("To Shopping Cart 2"),), ], ), ), ); } } class NoAnimationMaterialPageRoute<T> extends MaterialPageRoute<T> { NoAnimationMaterialPageRoute({ @required WidgetBuilder builder, RouteSettings settings, bool maintainState = true, bool fullscreenDialog = false, }) : super( builder: builder, maintainState: maintainState, settings: settings, fullscreenDialog: fullscreenDialog); @override Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) { return child; } }Modify animation (code from stack overflow)
- If you want to disable material Override the MaterialPAgeRoute<T> Class and modify buildtransitions by returning nothing in the child.
Location of Widget in the tree.
The BuildContext for a particular widget can change location over time as the widget is moved around the tree. Because of this, values returned from the methods on this class should not be cached beyond the execution of a single synchronous function.
@override
Widget build(BuildContext context) {
// here, Scaffold.of(context) returns null
return Scaffold(
appBar: AppBar(title: Text('Demo')),
body: Builder(
builder: (BuildContext context) {
return FlatButton(
child: Text('BUTTON'),
onPressed: () {
// here, Scaffold.of(context) returns the locally created Scaffold
Scaffold.of(context).showSnackBar(SnackBar(
content: Text('Hello.')
));
}
);
}
)
);
}
3. Navigation: Send new data to screen
TodosScreen({Key key, @required this.todos}) : super(key: key);
- It is a
,
-separated list of expressions that can access constructor parameters and can assign to instance fields, evenfinal
instance fields.- This is handy to initialize final fields with calculated values.
Sending Data to Another Screen
Initialiser ListDetailScreen({Key key, @required this.todo}) : super(key: key);
key
parameter passed to the constructor is forwarded to the named parameterkey
of the unnamed constructor of the super class.import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; class Todo { final String title; final String description; Todo(this.title, this.description); } void main() { runApp(MaterialApp( title: 'Passing Data', home: TodosScreen( todos: List.generate( 20, (i) => Todo( 'Todo $i', 'A description of what needs to be done for Todo $i', ), ), ), )); } class TodosScreen extends StatelessWidget { final List<Todo> todos; TodosScreen({Key key, @required this.todos}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Todos'), ), body: ListView.builder( itemCount: todos.length, itemBuilder: (context, index) { return ListTile( title: Text(todos[index].title), onTap: () { //Navigator.push(context, MaterialPageRoute(builder: (context) => DetailScreen(dtodo: todos[index]),),); Navigator.push(context, MaterialPageRoute(builder: (context) { return DetailScreen(dtodo: todos[index]);} ),//MaterialPageRoute );//Navigation }, ); }, ), ); } } class DetailScreen extends StatelessWidget { // Declare a field that holds the Todo final Todo dtodo; // In the constructor, require a Todo DetailScreen({Key key, @required this.dtodo}) : super(key: key); @override Widget build(BuildContext context) { // Use the Todo to create our UI return Scaffold( appBar: AppBar( title: Text("${dtodo.title}"), ), body: Padding( padding: EdgeInsets.all(16.0), child: Text('${dtodo.description}'), ), ); } }Heroes AnimationTo make your app more alive, add animation to the onClicked/Selected Widget e.g. Icon fly to the next page.Tag - IdentifierMake sure both page have the same tag.Hero( tag: "DeleteTag", child: Icon( Icons.delete, size: 50.0, ), ),
placeholderBuilder - Fill the empty space of the hero with a placeholderplaceholderBuilder: (context, widget) { return Container( height: 100.0, width: 100.0, child: CircularProgressIndicator(), ); }, ),flightShuttleBuilder - further customise the animation and iconflightShuttleBuilder: (flightContext, animation, direction, fromContext, toContext) { return Icon(FontAwesomeIcons.rocket, size: 150.0,); }, ),
Comments
Post a Comment