Layout Builder

Layout Builder is used to configure display mode, size, spacing, positioning, Flex/Grid and other layout properties when creating views. Basic writing is calling .layout(|layout| { ... }) after view, continuously calling layout methods in closure, finally returning modified layout.

Basic Writing

After importing LayoutBuilder, all views can call .layout(...). Also need to import LayoutResolverExt, so layout in closure can use display, size, flex_grow and other layout methods.

Following example uses flex related types, assuming you already enabled layout-flex feature.

use flor::taffy::{Dimension, Display, FlexDirection, LengthPercentage, Size};
use flor::view::builder::LayoutBuilder;
use flor::view::resolver::{LayoutResolverExt, Unit};
use flor::views;
use flor_lys::div::div;
use flor_lys::label::label;

let panel = div(views![label("Content")])
    .layout(|layout| {
        layout
            .display(Display::Flex)
            .flex_direction(FlexDirection::Column)
            .size(
                Size {
                    width: Dimension::Percent(1.0),
                    height: Dimension::Auto,
                },
                Size {
                    width: Unit::Px,
                    height: Unit::Px,
                },
            )
            .gap(
                Size {
                    width: LengthPercentage::Length(8.0),
                    height: LengthPercentage::Length(8.0),
                },
                Size {
                    width: Unit::Px,
                    height: Unit::Px,
                },
            )
    });

Closure must return modified layout. If closure captures external signal or variable, usually needs to write as move |layout| { ... }.

Flor currently doesn't have direct .width(100), .height(40), .x(10), .y(20) — these kinds of layout builder methods. Size, position, margin are all expressed through size, inset, margin and other layout parameters.

Chain Writing and set Writing

Most times directly chain calling is enough:

layout
    .display(Display::Flex)
    .flex_grow(1.0)

Each layout method also has a same-named set_ version, for example display(...) corresponds to set_display(...), flex_grow(...) corresponds to set_flex_grow(...). This group of set_ methods is suitable for branch modifying same layout in if, match.

These methods are automatically generated by Flor, so naming stays unified: layout item name written as snake_case method name, set_ version adds set_ in front. You just use method names in following table.

use flor::taffy::Display;
use flor::view::builder::LayoutBuilder;
use flor::view::resolver::LayoutResolverExt;
use flor_lys::label::label;

let item = label("Toggleable")
    .layout(move |mut layout| {
        if true {
            layout.set_display(Display::None);
        } else {
            layout.set_display(Display::Flex);
        }
        layout
    });

set_ methods are mainly used when view development, parsing atomic class assignment

State Layout

Layout can also be set separately by view state. After calling hover(), focus(), active() and other state methods, subsequent layout settings will write to corresponding state; calling normal() or base() can switch back to normal state.

MethodParameterPurpose
base() / normal()NoneSwitch back to normal state.
focus()NoneSubsequent layout items for focus state.
hover()NoneSubsequent layout items for hover state.
active()NoneSubsequent layout items for active state.
disabled()NoneSubsequent layout items for disabled state.
clear()NoneClear existing layout items.
use flor::taffy::{Display, FlexDirection};
use flor::view::builder::LayoutBuilder;
use flor::view::resolver::LayoutResolverExt;
use flor::views;
use flor_lys::div::div;
use flor_lys::label::label;

let view = div(views![label("Content")])
    .layout(|layout| {
        layout
            .display(Display::Flex)
            .flex_direction(FlexDirection::Column)
            .hover()
            .display(Display::None)
    });

How to Read Unit Parameters

Layout values mainly come from flor::taffy, unit types come from flor::view::resolver::Unit.

Unit is length unit. It only participates in conversion when layout value is length, finally resolves to px and hands to layout system.

UnitMeaningConversion Base
Unit::PxPixel.No conversion, whatever value is passed is the px value.
Unit::Ptpoint, common font/typesetting unit.Uses current window DPI conversion, formula is 1pt = dpi / 72 px. Normal layout length uses window's vertical DPI; window reads DPI from platform when creating, updates when DPI changes.
Unit::Remroot em.Uses current window's WindowOption::rem_px, default is 16.0, so default 1rem = 16px.
Unit::Vwviewport width.1vw = current window client area width / 100. Updates after window resize.
Unit::Vhviewport height.1vh = current window client area height / 100. Updates after window resize.

Whenever layout value and Unit appear together in method, rule is: layout value is responsible for expressing length, percent or auto, Unit only decides how to parse this number when value is length. For example Dimension::Length(12.0) paired with Unit::Px means 12px; Dimension::Percent(0.5) and Dimension::Auto don't depend on unit.

Core Layout Parameters

These methods are not affected by layout-flex, layout-grid, layout-block feature.

MethodParameterDescription
display(value)value: DisplaySet layout strategy, for example show, hide and flex/grid/block layout mode after enabling corresponding feature.
item_is_table(value)value: boolMark whether child item is processed as table item. Current table layout hasn't implemented, application code usually doesn't need to set it.
box_sizing(value)value: BoxSizingControl whether size, min_size, max_size and other size styles act on content box or border box.
overflow(value)value: Point<Overflow>Set overflow behavior in x/y two directions. Use Point { x, y } to separately pass horizontal and vertical Overflow.
scrollbar_width(width, unit)width: f32, unit: UnitReserve scrollbar space for Overflow::Scroll or Overflow::Auto. unit explains width's unit.
position(value)value: PositionSet element positioning method, decides which positioning baseline inset uses.
inset(value, units)value: Rect<LengthPercentageAuto>, units: Rect<Unit>Set left/right/top/bottom offset. Each edge's Length uses corresponding Unit to parse, Percent and Auto don't depend on unit.
size(value, units)value: Size<Dimension>, units: Size<Unit>Set initial width and height. value.width and value.height are width and height separately, units.width and units.height are length units.
min_size(value, units)value: Size<Dimension>, units: Size<Unit>Set minimum width and height, parameter structure same as size.
max_size(value, units)value: Size<Dimension>, units: Size<Unit>Set maximum width and height, parameter structure same as size.
aspect_ratio(value)value: f32Set preferred aspect ratio, calculation is width / height.
margin(value, units)value: Rect<LengthPercentageAuto>, units: Rect<Unit>Set outer margin. All four edges can use length, percent or auto.
padding(value, units)value: Rect<LengthPercentage>, units: Rect<Unit>Set inner padding. All four edges can use length or percent, doesn't support auto.
border(value, units)value: Rect<LengthPercentage>, units: Rect<Unit>Set layout-level border thickness. All four edges can use length or percent, doesn't support auto.

Example:

use flor::taffy::{Dimension, LengthPercentageAuto, Rect, Size};
use flor::view::builder::LayoutBuilder;
use flor::view::resolver::{LayoutResolverExt, Unit};
use flor::views;
use flor_lys::div::div;
use flor_lys::label::label;

let view = div(views![label("Content")])
    .layout(|layout| {
        layout
            .size(
                Size {
                    width: Dimension::Length(320.0),
                    height: Dimension::Auto,
                },
                Size {
                    width: Unit::Px,
                    height: Unit::Px,
                },
            )
            .margin(
                Rect {
                    left: LengthPercentageAuto::Length(12.0),
                    right: LengthPercentageAuto::Length(12.0),
                    top: LengthPercentageAuto::Length(8.0),
                    bottom: LengthPercentageAuto::Length(8.0),
                },
                Rect {
                    left: Unit::Px,
                    right: Unit::Px,
                    top: Unit::Px,
                    bottom: Unit::Px,
                },
            )
    });

Flex and Grid Shared Parameters

These methods are available after enabling either layout-flex or layout-grid feature.

MethodParameterDescription
align_items(value)value: AlignItemsSet how child items align on cross/block axis.
align_self(value)value: AlignSelfSet how current node itself aligns on cross/block axis; falls back to parent's align_items when not set.
align_content(value)value: AlignContentSet how container content distributes on cross/block axis.
justify_content(value)value: JustifyContentSet how container content distributes on main/inline axis.
gap(value, units)value: Size<LengthPercentage>, units: Size<Unit>Set item spacing in two directions. Field names follow Taffy's Size { width, height }, corresponding length values separately use units.width and units.height to parse.

Block Parameters

These methods require enabling layout-block feature.

MethodParameterDescription
text_align(value)value: TextAlignSet inline direction alignment in block layout.

Flex Parameters

These methods require enabling layout-flex feature.

MethodParameterDescription
flex_direction(value)value: FlexDirectionSet flex main axis direction.
flex_wrap(value)value: FlexWrapSet whether flex child items wrap.
flex_basis(value, unit)value: Dimension, unit: UnitSet flex child item initial main axis size. Dimension::Length uses unit to parse, Percent and Auto don't depend on unit.
flex_grow(value)value: f32Set remaining space growth ratio. Default value is 0.0, passing positive number means participating in growth.
flex_shrink(value)value: f32Set shrink ratio when space insufficient. Default value is 1.0, passing positive number means participating in shrink.

Example:

use flor::taffy::{AlignItems, Display, FlexDirection, JustifyContent};
use flor::view::builder::LayoutBuilder;
use flor::view::resolver::LayoutResolverExt;
use flor::views;
use flor_lys::div::div;
use flor_lys::label::label;

let toolbar = div(views![label("Left"), label("Right")])
    .layout(|layout| {
        layout
            .display(Display::Flex)
            .flex_direction(FlexDirection::Row)
            .align_items(AlignItems::Center)
            .justify_content(JustifyContent::SpaceBetween)
    });

Grid Parameters

These methods require enabling layout-grid feature.

MethodParameterDescription
justify_items(value)value: AlignItemsSet how grid child items align on inline axis.
justify_self(value)value: AlignSelfSet how current grid child item itself aligns on inline axis; falls back to parent's justify_items when not set.
grid_template_rows(value)value: Vec<(TrackSizingFunction, Unit)>Set explicit grid row track size. Each track carries a Unit, used to parse length values in that track.
grid_template_columns(value)value: Vec<(TrackSizingFunction, Unit)>Set explicit grid column track size. Each track carries a Unit, used to parse length values in that track.
grid_auto_rows(value)value: Vec<(NonRepeatedTrackSizingFunction, Unit)>Set implicitly created grid row size.
grid_auto_columns(value)value: Vec<(NonRepeatedTrackSizingFunction, Unit)>Set implicitly created grid column size.
grid_auto_flow(value)value: GridAutoFlowSet automatic placement of grid item flow.
grid_row(value)value: Line<GridPlacement>Set current child item's start/end position in grid row direction.
grid_column(value)value: Line<GridPlacement>Set current child item's start/end position in grid column direction.

Availability Quick Reference

Methodfeature
display, item_is_table, box_sizing, overflow, scrollbar_width, position, inset, size, min_size, max_size, aspect_ratio, margin, padding, borderAlways generated
align_items, align_self, align_content, justify_content, gaplayout-flex or layout-grid
text_alignlayout-block
flex_direction, flex_wrap, flex_basis, flex_grow, flex_shrinklayout-flex
justify_items, justify_self, grid_template_rows, grid_template_columns, grid_auto_rows, grid_auto_columns, grid_auto_flow, grid_row, grid_columnlayout-grid