Creating widget layouts

Overview

In Flutter, widget trees are built by passing a child or children. Widget trees have a lot of indentation, especially since in Flutter nearly everything is a widget, and composition is preferred to inheritance. This can lead to complex nesting and child parameters.

Flutter-views are optimised for building widget trees. Pug in particular is well suited for creating tree structures and moving parts around.

The following example generates a Dart method FooPage(), which returns a Scaffold with an AppBar, and a centralized greeting message.

The Pug creates the layout, and the main.dart file uses this layout to render the app. This separation between layout and logic is fundamental to using flutter-view.

foo-page.pug
foo-page(flutter-view :greeting)
    scaffold
        app-bar(as='appBar')
            container(as='title') Foo Page
        center(as='body') Hello $greeting!

Adding children to widgets

In a flutter-view, add indented child tags to tags to automatically have them assigned as child or children parameters.

In flutter-view Pug/HTML content, an HTML tag is a method or constructor call, and its parameters are parameters for this method or constructor. The tag children are assigned as the Flutter child/children parameters.

To see how this works, compare the Pug and generated Dart code in this example:

container
    column
        row 
            text(value='first row!')
        row 
            text(value='second row!')
        row
            flat-button 
                text(value='Click me!')
            

Automatic columns

Flutter-view knows which classes generally need children instead of single child, and automatically creates Columns when you pass multiple children. Also, if you pass text, flutter-view it automatically wraps it in a Text widget as well. This together allows you to be more terse:

container
    row first row!
    row second row!
    row
        flat-button Click me!            

You can override the default wrapper in flutter-view.json.

Calling dart factory constructors

Some Flutter Dart classes may use factory constructors. For example, ButtonTheme has a ButtonTheme.bar() constructor.

To call the factory constructor instead of the default constructor, pass the constructor after the class name, separated with a colon.

button-theme:bar
    | some content here

Passing children instead of child

There may be cases where flutter-view does not recognise your tag needs a children parameter instead of a child parameter. In that case use and array and assign it as children:

column
    array(as='children')
        row first!
        row second!

Passing const widgets

For optimising performance, you may want to pass some widgets as constants. You can do this by adding a const parameter in a widget:

To see how this works, compare the Pug and generated Dart code in this example:

container
    column(const)
        row 
            text(value='first row!')

Passing parameters

To pass parameters besides child or children, you pass them as pug/html parameters.

String parameters

You can pass strings by using quotes. Both double and single quotes work.

For example:

banner(title='testing')
    | Hello world!

Expression parameters

To assign a Dart expression as the value of a parameter:

  • start the parameter name with :

  • wrap the expression in quotes. You may need to escape strings.

For example:

flat-button(:color='highlighted ? Colors.red : Colors.grey')
    | Click me!     

For title we want to pass a direct string, but for color we want to pass a value by reference, so we add : in front of the parameter.

Unnamed parameters

Some widgets take an unnamed parameter in their constructor. You can pass this using the reserved value parameter:

container
    icon(:value='Icons.add')
    text(value='Hello world')

Escaping parameter names

You may need to pass a parameter that has the name of a reserved keyword, such as value. You can bypass this problem by escaping your parameter with the ^ sign:

:^value='foo'

Passing complex parameter values

Sometimes what you want to pass is not just a single value, but a value that is constructed of many widgets. To solve this, you may take a child and use the as keyword to assign it as a parameter to the parent widget.

scaffold
    app-bar(as='appBar')
        container(as='title') Test App
    center(as='body') Hello world!

The Scaffold class used above has no child or children parameters. Instead we add two children and assign them as parameters using the as property.

Passing functions as children

You can create functions that return children using the function shortcut.

Passing handlers

Passing a handler function or closure is no different than in Dart:

my-button(flutter-view :on-click[Function])
    flat-button(:on-pressed='onClick') Click me!

A common case is a closure without any parameters. In that case you can use the @ sign to create a closure handler:

my-button(flutter-view)
    flat-button(@on-pressed='print("Click!")') Click me!

Passing Arrays

Sometimes you need to pass an array of specific items to a parameter. In that case you can use the array tag.

custom-scroll-view
    array(as='slivers')
        sliver1
        sliver2
        sliver3

Automatic Containers

A nice Pug feature is that classes and ids are automatically converted into DIV tags. In flutter-view, they are automatically converted into Container widgets:

container hello world
#greeting hello world
.greeting hello world

All three are equivalent and convert to:

Container(
    child: Text('hello world'),
)

The classes and ids you use are forgotten after the conversion to Dart code. However, you do get automatic commenting, which will make it easier to read the generated code.

The biggest benefit is however that you can use them to style your widgets.

Last updated