Flutter Widgets

What's covered?

What's a Widget?

In Flutter, everything is a widget.

If you've worked with React or Vue before, this'll be easy. Everything inFlutter is a Widget, much like in JS frameworks you're working with smallreusable components. And a Widget is nothing more than a Dart class that extends a Flutter class.

All Flutter widgets look like this:

  1. class ImageWidget extends StatelessWidget {
  2. // class stuff
  3. }

Widget classes have (usually) only one requirement: it must have a buildmethod which returns other Widgets. The only exception to this rule is low-level widgets like 'Text' that return primitive types (Strings or numbers, usually.)

  1. class BigText extends StatelessWidget {
  2. Widget build(context) {
  3. return new Text('text');
  4. }
  5. }

Other than that, a widget is just a normal Dart class. You can add methods and properties and the like.

  1. class BigText extends StatelessWidget {
  2. // a property on this class
  3. final String text;
  4. // a constructor for this class
  5. BigText(this.text);
  6. Widget build(context) {
  7. // Pass the text down to another widget
  8. return new Text(
  9. text,
  10. // Even changing font-style is done through a Dart class.
  11. textStyle: new TextStyle(fontSize: 20.0),
  12. );
  13. }
  14. }

Then somewhere else in an app you'd use the widget like this:

  1. // ...
  2. // This is how we'd use the BigText within another widget.
  3. child: new BigText('This string would render and be big'),
  4. // ...

Stateless and StatefulWidgets

Flutter widgets must extend a handful of classes from the Flutter library. The two you'll use almost always are StatelessWidget and StatefulWidget.

The difference is that one has a concept of state within the Widget and some built in methods that tells Flutter to re-render if that state changes. This is a key concept in Flutter.

A Stateful Widget looks a bit different. It's actually two classes: the state objectand the widget. This is how you'd write it:

  1. class Counter extends StatefulWidget {
  2. Counter({Key key, this.title}) : super(key: key);
  3. // Stateful Widgets don't have build methods.
  4. // They have createState() methods.
  5. // Create State returns a class that extends Flutters State class.
  6. @override
  7. _MyHomePageState createState() => new _MyHomePageState();
  8. // Stateful Widgets are rarely more complicated than this.
  9. }
  10. class _MyHomePageState extends State<MyHomePage> {
  11. int counter = 0;
  12. void increaseCount() {
  13. // setState is a special method that tells Flutter to repaint
  14. // the view because state has been updated!
  15. setState(() {
  16. this.counter++;
  17. }
  18. }
  19. // gotta have that build method!
  20. Widget build(context) {
  21. return new RaisedButton(
  22. onPressed: increaseCount,
  23. child: new Text('Tap to Increase'),
  24. );
  25. }
  26. }

Material and Cupertino Widgets

The Flutter SDK is extra nice because there are loads of built in widgets in thestyle of Android and iOS.

I'm sorry for gushing, but it's actually quite amazing what Flutter gives you outof the box. You can create pretty damn good looking and accessible mobileapps with no design chops at all.

Imagine if you started a new React, Vue, React Native, etc project, and it cameready with hundreds of components that we're just ready to go with designstandards in mind. That's what Material and Cupertino widgets are — Materialwidgets are designed to look like Android apps and Cupertino like iOS.

These built in Widgets and the ability to create completely custom widgetsgives you a lot of power. You can create a completely custom app withlower-level custom widgets, or you can just use what you're given to get to MVP.

Most Common Widgets

These are the widgets that are ready to go, out of the box, and you'll want toget very comfortable with:

  • Text - A widget used to simply simply text on the screen.
  • Image - For displaying images.
  • Icon - For displaying Flutter's built in Material and Cupertino icons.
  • Container - The div of Flutter UI. It's a convenience widget that allowsyou to add padding, alignment, backgrounds, force sizes on widgets, andboatloads of other things. It also takes up 0px space when empty, which comesin handy.
  • TextInput - To handle user feedback.
  • Row, Column - These are widgets that display a list of children in horizontalor vertical directions. They follow flex-box rules for layout, if you'recoming from the web and know CSS.
  • Stack - A stack displays a list of children on top of one and other. Thisfunctions much like the 'position' property in CSS.
  • Scaffold - This is the root of every page in your app, which gives your appa basic layout structure. It makes it easy to implement bottom navigations,appBars, back buttons, etc.

The widget documentation is very good in Flutter. Checkout the catalogue.

NB: If you're familiar with component based frameworks like React, youprobablydon't need to read this. Widgets are just components.

Thinking in Widgets

In Flutter, everything is a widget. Widgets are just tiny chunks ofUI that you can combine to make a complete app. Building an app Flutter islike building a lego set — piece by piece.

Widgets are nested inside of eachother to build your app. Even the root of yourapp is just a widget. It's widgets all the way down.

Flutter is unique in that every aspect of UI is handled with Widgets.

A widget might display something, it might help define design, it might helpwith layout, or it may handle interaction. I really can't exclaim this enough:everything is a widget

  • A simple widget that displays text: const Text('Hello World').
  • A simple widget that a user interacts with const Button(onTap: …callback…)
  • A simple widget that adds a background color: const BoxDecoration(background: Colors.blue)

Basically, imagine that your CSS, HTML, and JavaScript are all handled bywidgets. There is no markup language. There is no CSS. Just widgets.

Widget Hierarchy

In this picture, every thing that's outlined is a widget:

Outlined widgets

This picture is from one of the tutorial apps on FlutterByExample, and this isa detail page, of which there is one for every dog in the app.

The green outline represents the page. And a page in Flutter is awidget. The blue outlines represent pieces of UI that logically group together.The rest are outlined white, and they're simply dumb components that have noconcern over their content, they just display what they're told.

This is the widget hierarchy for this page:

  • PageWidget

    • DogProfileWidget
    • CircleImage
    • Text
    • Text
    • Text
    • Container

      • Icon
      • Text
    • RateDogWidget
    • Slider
    • Text
    • SubmitButton

NB This isn't exactly accurate, there are layout widgetssuch ascolumnsand padding in here that I'm glossing over.

Design for Re-usability

The most important part of using Flutter Widgets effectively is designing yourlowest level widgets to be reusable.

For example, the CircleImage widget from the image above:

  1. class CircleImage extends StatelessWidget {
  2. final String renderUrl;
  3. CircleImage(this.renderUrl);
  4. @override
  5. Widget build(BuildContext context) {
  6. return new Container(
  7. width: 100.0,
  8. height: 100.0,
  9. decoration: new BoxDecoration(
  10. shape: BoxShape.circle,
  11. image: new DecorationImage(
  12. fit: BoxFit.cover,
  13. image: new NetworkImage(renderUrl ?? ''),
  14. ),
  15. ),
  16. );
  17. }
  18. }

Then, anywhere in your app, you can reuse this Widget: new CircleImage('https..).This component is designed for re-usability because anywhere in your app thatyou may want a round image of a certain size, you can just pass in a url andthere you have it. There's no need to re-write this widget over and over.

And, this circle image doesn't care at all about what it's displaying. It'sjust enforcing styles.

In the test app that these images are from, I also have a list of all the dogsin the app. Heres a picture of one of the cards:

Dog card

In that Widget, I don't need to rewrite the circle image, because I've alreadybuilt it once.