# Flutter A quick cheatsheet of useful snippet for Flutter ## Widget A widget is the basic type of controller in _Flutter Material_. There are two type of basic Widget we can extend our classes: `StefulWidget` or `StatelessWidget`. ### Stateful **StatefulWidget** are all the widget that interally have a dynamic value that can change during usage. It can receive an input value in the constructor or reference to functions. You need to create two classes like: ``` class BasePage extends StatefulWidget { State createState() { return _BasePageState(); } } class _BasePageState extends State { int _value = 0; void _increment() { setState(() { _value++; }); } } ``` When you are going to update the value you need to wrap it in `setState(() {})` function. ### Stateless **StatelessWidget** are components that are rendered and keep that value. A refresh by a parent is needed to update the content. It can receive a value from the constructor. ## UI ### Icon & Splashpage https://flutter.io/assets-and-images/#updating-the-launch-screen ### Screen Size `Size(MediaQuery.of(context).size.width` ### Colors & Themes You can acces colors using `Colors.white`. Each color has an extra parameter `withOpacity()` you can use to set the opacity. You can use theme colors using `Theme.of(context).accentColor` ### Styling You can add extra style (background color, rounded corners, etc) to a widget using `DecoratedBox`. ``` DecorationBox(decoration: BoxDecoration()); ``` ## Layout `ListView` acts like a good stack for put elements in colums. If it contains only an object, use `SingleChildScrollView`. Either `Column` and `Row` are ok but doesn't support scroll. If you want to widget in a column/row to take as much space as possible wrap it in `Expanded`. `Flexible` is also available and you can provide which priority on weight the widget will have. Both `Expanded` and `Flexible` accept a `flex` param, where you can pass a weight. `SizeBox` is a widget with fixed size, it is useful e.g. to add simple margin between widgets. `Container` is a box where you can add your Widget and set some params like _margin_, _padding_, _color_, _decoration_, etc. ## Navigation ### Route to other page without back (eg android final) ``` Navigator.pushReplacement( context, MaterialPageRoute( builder: (BuildContext context) => Class( param: value, ), )), ``` ### Route to other page with back ``` Navigator.push( context, MaterialPageRoute( builder: (BuildContext context) => Class( param: value, ), )), ``` ### Back (Basic) `Navigator.pop(context);` ### Back (Passing data) `Navigator.pop(context, back_value);` Edit Navigator.push[…].then((type value) {}) adding future type ## Sidebar ### Add left drawer In the drawer we can list several entries, each of those can have (or not) an Icon. ``` New Scaffold(drawer: Drawer(child: Column(children: [ AppBar(title: Text(‘Choose’), AutomaticallyImplyLeading: false ), ListTile( leading: Icon(Icons.list), title: Text(’Some Text’), onTap: () {} ) ]) ``` ### Add right drawer `New Scaffold(endDrawer:` ## Tabs Body of Scaffold needs to have TabBarView to manage switch between tabs contents. The number in length is mandatory to be the same of the items in the TabBarView and TabBar tabs. The pages has not to be Scaffold Widget, but directly the body because them are in the TabBarView that has already a Scaffold. ### Add drawer with tab on top like Android ``` DefaultTabController(length: 2, child: Scaffold( body: TabBarView(), appBar: AppBar(bottom: TabBar(tabs: [ Tab(icon:, text:) ]) ``` ### Add drawer with tab on Botton like iOS ``` DefaultTabController(length: 2, child: Scaffold( body: TabBarView(), bottomNavigationBar: TabBar(tabs: [ Tab() ]) ``` ## Routing Add in main MaterialApp a new key routes that support a map. ``` routes: { “/“: (BuilderContext context) => HomeClass() “/admin”: (BuilderContext context) => AdminClass() } ``` Then in every part of the app you can call .pushReplacementNamed(‘/admin’, context); Note: If you set “/“ you have to remove the home value in the material app or an error will raise. ### Pass value in routes Instead of using routes, you need to use onGenerateRoutes key. If a route is already defined in routes it will raise an error. ``` onGenerateRoutes: (RouteSetting settings) { final List pathElements = settings.name.split(“/“); if(pathElements[0] != “”) { return null; } if(pathElements[1] == ‘product’) { final int index = int.parse(pathElements[2]); return MaterialPageRoute(builder: (BuilderContext context) => ProductPage(_products[index])) } return null; } ``` In this scenario the main file has to be converted in StatefulWidget to centralise where the variables are stored. In the example I set MaterialPageRoute to return a bool, but we can se that to every other type. Then you can call .pushNamed(context, ‘/product/‘ + index.toString()) Also there’s a fallback for not registered route onUnkownRoute. ## Alert showDialog using an AlertDialog as Widget. ``` showDialog(context: context, builder: (BuilderContext context) { return AlertDialog( title: Text(), content: Text(), actions: [ FlatButton(child: Text(), onPressed: () { Navigator.pop(context); // close the dialog }) ] } ``` ## Modal ``` showModalButtonSheet(context: context, builder: (BuilderContext context) { return Center( child: Text() ); } ``` ## Textfield In order to add a _title_ we need to use `InputDecoration(labelText:)`. In order to set a custom keyboard use `InputDecoration(keyboardType: (true|false))`. In order to handle password use `InputDecoration(obscureText: (true|false)`. In order to get the value `onChanged: (value) {}`. In order to monitor the value you need a `StatefulWidget`. ## AppBar AppBar component allow you to set _title_, _back_ and _actions_ for the status bar. `title` contains the title for widget. `actions` is an array of widgets that stay on the right.