Skip to content

Custom Widgets

Umberto Sonnino edited this page Jul 16, 2018 · 1 revision

The TV App and the Tablet App relied heavily on drawing custom components.
Flutter exposes many of the internal mechanics, and the available documentation details very well how to tie everything together.

Let's take a look at how this repository has used custom widgets, and drawn directly to canvas in order to fulfill its needs in terms of UI and UX.

Custom Widget

A good example of a custom widget is the Flare Heart Widget that's used in the TV App and the Tablet App.

The Dart file contains two classes:

  • FlareHeart that extends LeafRenderObjectWidget
  • HeartRenderObject that extends RenderBox (i.e. a `RenderObject)

LeafRenderObjectWidget

This class (docs) is a Widget: it can be inserted in any widget tree without as any other default component:

[...]
new Container(
  child: new FlareHeart("assets/flares/Heart", isDead)
)
[...]

This snippet can be included in your widget tree (an example can be found here), delegating the layout and painting operations to the underlying RenderObject.

The LeafRenderObjectWidget is thus responsible for having a constructor and wrapping the values that the RenderObject needs.

The following two overrides are also fundamental:

  • createRenderObject
    Instantiates the actual RenderObject in the Widget Tree;
  • updateRenderObject
    Any change to the parameters that are passed to the Widget can be reflected also on the UI, if needed. Updating a RenderObject will cause the object to redraw.

RenderObject

As specified in the docs, this is an object in the render tree, and it defines what and how its creator Widget will paint on the screen.

The key overrides here are:

  • performLayout()
    Whenever the size or constraints change on the current RenderObject, new calculations might need to be made to properly (re)position the object. This function call can be overridden to perform those calculations, and keep them separate from the painting function call, which can happen in a different point in time.
  • paint()
    The current PaintingContext exposes the canvas, and this class can draw, taking full advantage of the exposed API.
    In our Flare Heart example, it's the Flare library that, granted access to the canvas, draws on the screen; this function is responsible for the correct positioning, as well as calling the library operation.

There are also a number of getters and setters for various properties so that when the LeafRenderObjectWidget calls its update function, those changes are also shown.

Lastly, since the Flare library needs to advance the animation every frame, a beginFrame function is recursively pushed onto the current SchedulerBinding instance.

This is just a brief overview of how the Flutter Hot Reload Game components were used to create the whole experience.