Skip to content

chooyan-eng/graph_your_widget_tree

Repository files navigation

graph_your_widget_tree

graph_your_widget_tree provides Graph widget that renders a model of a widget tree represented by WidgetEntry and its children.

This package mainly aims to be used with other packages making slide decks, such as flutter_deck or slick_slides, not for production apps.

Features

This packages provides the features of

  • Rendering a graph of a widget tree
  • Styling each node of the widgets
  • Detecting events from the widget tree
  • Notifying the result of layout calculation in detail

Every features is for making your slide decks more interactive.

Getting started

As an quick introduction, you can place Graph widget like the code below.

Graph(
  root: WidgetEntry.single(
    name: 'MaterialApp',
    child: WidgetEntry.leaf(name: 'Scaffold'),
  ),
),

This Graph with root WidgetEntry named 'MaterialApp' and its child 'Scaffold' will draw the widget tree like below.

A picture of a simple widget tree

Usage

Basics

To make a graph of a widget tree, place Graph widget wherever you want to draw.

Graph(),

Graph requires a WidgetEntry object as a root of the widget tree.

Graph(
  root: WidgetEntry.single(),
)

WidgetEntry represents one node of the widget tree. As Flutter widgets has 3 patterns that

  • Have one child, such like SizedBox, Center
  • Have multiple children, such like Column, Stack
  • Have no child, leaf in other words, such like Image, RichText

Therefore, WidgetEntry has three types of constructors, WidgetEntry.single(), WidgetEntry.multiple(), and WidgetEntry.leaf().

All you need to do is to describe the structure of the widget tree with WidgetEntry and pass the root of the nodes to Graph.

For example, if the code below is run,

Graph(
  root: WidgetEntry.single(
    name: 'MaterialApp',
    child: WidgetEntry.multiple(
      name: 'Scaffold',
      children: [
        WidgetEntry.multiple(
          name: 'AppBar', 
          children: [
            WidgetEntry.single(
              name: 'IconButton',
              child: WidgetEntry.leaf(name: 'Icon'),
            ),
          ],
        ),
        WidgetEntry.multiple(
          name: 'Column', children: [
            WidgetEntry.leaf(name: 'Text'),
            WidgetEntry.leaf(name: 'Text'),
          ],
        ),
        WidgetEntry.leaf(
          name: 'Floating\nActionButton',
        ),
      ],
    ),
  ),
),

This will render the widget tree below

An image of a sample widget tree

Styles

Each WidgetEntry can be styled using GraphTheme.

As GraphTheme is an InheritedWidget, you can place this wherever you want as long as it is an ancestor of Graph.

GraphTheme(
  child: Graph(),
),

GraphTheme has two options for styling, defaultTheme and extraThemes.

defaultTheme is applied to all the WidgetEntrys as a default style.

For example, you can make all the texts and the borders of the boxes with the code below.

GraphTheme(
  child: Graph(),
  defaultTheme: const GraphThemeData(
    textStyle: TextStyle(fontWeight: FontWeight.w800),
    borderWidth: 4,
  ),
),

An image of bolded text and boxes

extraThemes is for styling specific WidgetEntrys individually.

As the type of extraThemes is Map<Enum, GraphThemeData>, you can define any enum type as keys of extraThemes and can set associated GraphThemeData as values.

enum WidgetAppearance { normal, focused, disabled }

GraphTheme(
  defaultTheme: const GraphThemeData(),
  extraThemes: const {
    WidgetAppearance.focused: GraphThemeData(
      textStyle: TextStyle(color: Colors.blue),
      borderWidth: 4,
      borderColor: Colors.blue,
    ),  
    WidgetAppearance.disabled: GraphThemeData(
      textStyle: TextStyle(color: Colors.grey),
      borderWidth: 1,
      borderColor: Colors.grey,
    ),  
  },
  child: Graph(),
),

Then, if you want to apply one of the extraThemes to WidgetEntry, set type by passing one of the keys of extraThemes, WidgetAppearance.focused or WidgetAppearance.disabled in this case.

When you set WidgetAppearance.focused to WidgetEntry of 'IconButton', and WidgetAppearance.disabled to `FloatingActionButton',

Graph(
  root: WidgetEntry.single(
    name: 'MaterialApp',
    child: WidgetEntry.multiple(
      name: 'Scaffold',
      children: [
        WidgetEntry.multiple(
          name: 'AppBar',
          children: [
            WidgetEntry.single(
              name: 'IconButton',
              child: WidgetEntry.leaf(name: 'Icon'),
              type: WidgetAppearance.focused,
            ),
          ],
        ),
        WidgetEntry.multiple(
          name: 'Column',
          children: [
            WidgetEntry.leaf(name: 'Text'),
            WidgetEntry.leaf(name: 'Text'),
          ],
        ),
        WidgetEntry.leaf(
          name: 'Floating\nActionButton',
          type: WidgetAppearance.disabled,
        ),
      ],
    ),
  ),
),

Graph will render the widget tree below.

An image of styled boxes

Rebuilding and updating the UI

As all the layouts and styles are updated on every rebuilding, you can manage the state of 'how each widget should be displayed' with whatever method you want, such as StatefulWidget, riverpod or even Get.

This enables you to make slide decks with dinamically animating widget trees.

Events

Graph has currently 2 callbacks onHover and onTap. Both callbacks are called when each event happens on a WidgetEntry.

Graph(
  onHover: (entry) {
    log('hovered: ${entry?.name}');
  },
  onTap: (entry) {
    log('tapped: ${entry.name}');
  },
)

Notification

By placing NotificationListener<RenderDetailNotification> somewhere above Graph, you can listen every update of a rendered widget tree.

NotificationListener<RenderDetailNotification> {
  onNotification: (notification) {
    // Do something with the rendered detail.
    return false;
  },
  child: SomeWidget(
    child: Graph(),
  ),
}

As notification has all the detail about rendered widgets on Graph, it enables you to overlay additional widgets based on positions of the widgets.

See Flutter doc for more information about NotificationListener.

About

A Flutter package drawing a widget tree for slide decks.

Resources

License

Stars

Watchers

Forks

Packages

No packages published