Flutter Essentials
This section is not intended to teach you Flutter, there are other resources for that, including the documentation and videos from Google.
This section points out the minimal ideas you need to understand to get started prototyping Flutter UIs using AFib.
Learn the Basic Conventions
Everything is a Widget
When you generate an AFib UI element, your ultimate goal is to return a Widget. AFib will pre-populate the top-level widget you are going to return for Screens, Dialogs, Drawers, and Bottom Sheets, so you need only fill in the content below that Widget.
Screens should always have a Scaffold
AFib will automatically declare a Scaffold at the root of your screen. The Scaffold constructor takes a large number of optional parameters related to material design, and you may assume that if you aren't using Material design, you don't want a Scaffold.
However, the Scaffold is also the basis for Flutter's entire styling system, so you should always start with it. If you don't want material design, you can simply omit all the material design related parameters.
Child/Children
Most Widgets in AFib can have either a single child Widget, or a list of children Widgets. For example, a button has a single child Widget.
final button = TextButton(
// the button's child is another widget.
child: Text("Add"),
onPressed: () => context.log?.d("Pressed add");
)
While a ListView has a list of children:
final rows = <Widget>[];
rows.add(Text("Item 1"));
rows.add(Text("Item 2"));
final list = ListView(
children: rows
);
So, when you build a Flutter UI, you are building a hierarchy of widgets. For example, your first screen might start with a Scaffold
(the top level Widget that AFib will provide for you). Below that might be a ListView
, perhaps populated with set of ListTiles
, each with a Text
child.
The UI Build Model and Keys
Like React/Redux, the Widget hierarchy you are building is conceptual. Flutter can difference one conceptual hierarchy from another, and then update only those parts of the screen that changed. As a result, you can 'rebuild' your entire UI each time you render, but still achieve extremely fast performance on screen.
In lists of Widgets, Flutter needs a unique ID so that it can determine how the conceptual list maps to the physical display (also just like React). Flutter uses a Key for that purpose. AFib provides the notion of a widget id, which you can easily convert into a Flutter Key using the keyForWID
method on the theme:
final t = spi.theme; // the spi and theme are described more below.
for(final todo in todoItems) {
rows.add(ListTile(
key: t.keyForWID(TDLEWidgetID.todoListItem.with1(todo.id))
...
);
}
Learn the Minimal Core Widgets
If Flutter has a problem, it is that it provides you with so many powerful widgets out of the box that it can be hard to get a grip on them. The widgets are often so flexible, that the solution to whatever you are trying to achieve is hiding in plain sight, just one constructor parameter away.
You can start learning about Flutter widgets using the Widget of the Week videos on Flutter's YouTube channel. You can see the Flutter Widget catalog.
PENDING: Play with the app-demo-uilab
Sample
I ultimately hope to create an app-demo-uilab
project style, which will show how you should work with all the Flutter native Widgets, and demonstrate driving them through AFib's UI testing framework. But, this work is still pending, and isn't really justified unless AFib sees significant adoption.
Since AFib's current build/smoketest creates all the standard project styles, and then runs their tests, completing this new project style would also include UI-level test coverage significantly.