Skip to content
Romain Rastel edited this page Dec 28, 2021 · 3 revisions

Woven Layout

The Woven layout is one of the four types of Image lists, showcased in Material Design.

It is implemented as a specific GridDelegate and can be used with the Flutter built-in widgets called SliverGrid and GridView.

GridView.custom(
  gridDelegate: SliverWovenGridDelegate.count(
    crossAxisCount: 2,
    mainAxisSpacing: 8,
    crossAxisSpacing: 8,
    pattern: [
      WovenGridTile(1),
      WovenGridTile(
        5 / 7,
        crossAxisRatio: 0.9,
        alignment: AlignmentDirectional.centerEnd,
      ),
    ],
  ),
  childrenDelegate: SliverChildBuilderDelegate(
    (context, index) => Tile(index: index),
  ),
);

Constructors

This SliverWovenGridDelegate has two constructors.

The count constructor

This constructor is used to divide the cross axis by a specific number, whatever the available size is. You can control this through the crossAxisCount parameter.

Use this constructor when you want to always have the same number of division in the cross axis extent.

The extent constructor

This constructor is used to set a maximum extent for each division in the cross axis. You can control this through the maxCrossAxisExtent parameter.

For example, in the case of a vertical 408px wide grid and without spacings between tiles, if you set the maxCrossAxisExtent to 204, the grid will have two 204px wide columns. If you set the maxCrossAxisExtent to 150, it will have three 136px wide columns (because the layout will try to give has mush space to each column without exceeding 150px).

Use this constructor when you want to show more or less items in the cross axis extent depending on the available space.

Pattern

The pattern is a list of WovenGridTile. Each tile indicates:

  • Its aspectRatio, which is the cross axis extent of the tile divided by its main axis extent.
  • Its crossAxisRatio, a number between 0 and 1 (defaults to 1), which indicates the ratio between the available space in the cross axis and the cross axis extent of the tile.
  • Its alignment, which determine how the tile is aligned within its available space when the crossAxisRatio is less than 1.

Anatomy of a pattern

The grid below can be obtained with the following pattern with a spacing in both directions set to 4:

pattern: [
  WovenGridTile(1),
  WovenGridTile(
    5 / 7,
    crossAxisRatio: 0.9,
    alignment: AlignmentDirectional.centerEnd,
  ),
],

The tiles 0 and 3 are defined by

WovenGridTile(1)

The tiles 1 and 2 are defined by

WovenGridTile(
  5 / 7,
  crossAxisRatio: 0.9,
  alignment: AlignmentDirectional.centerEnd,
),

In the case of a 204px wide grid this is how we can compute the height and width of these tiles:

  • The grid is divided in two 100px wide columns with a spacing of 4px between the columns.
  • The tiles 0 and 3 have a height and width equals to 100px (1.0 * 100).
  • The tiles 1 and 2 have a width equals to 90px (0.9 * 100) and a height equals to 126 (90 * 7 / 5).
  • The tiles 1 and 2 have an alignment set to AlignmentDirectional.centerEnd.

The arrow represents the direction used by the alignment to place the tiles:

  • In the first row we have a left-to-right direction.
  • In the second row we have a right-to-left direction. That's why in the second row the end represents the left side.

Alignement

centerEnd

center

centerStart

TileBottomSpace

To respect the Material Guidelines, you can also set a parameter called tileBottomSpace which adds a specifc amount of space below the tile. This space is intended to be used for displaying a text describing the tile. If you use this feature, your widget should have the same amount of pixels for this part.

TextDirection

This layout uses the ambient TextDirection to know if it should create the grid from left-to-right or right-to-left.

Just add a Directionality widget above the GridView (or CustomScrollView) to set the order in which the tiles are rendered.

Directionality(
  textDirection: TextDirection.rtl,
  child: GridView.custom(
    gridDelegate: SliverWovenGridDelegate.count(
      crossAxisCount: 2,
      mainAxisSpacing: 8,
      crossAxisSpacing: 8,
      pattern: [
        WovenGridTile(1),
        WovenGridTile(
          5 / 7,
          crossAxisRatio: 0.9,
          alignment: AlignmentDirectional.centerEnd,
        ),
      ],
    ),
    childrenDelegate: SliverChildBuilderDelegate(
      (context, index) => Tile(index: index),
    ),
  ),
),