Skip to main content

Scaffold

Struct Scaffold 

Source
pub struct Scaffold<Msg = Callback> { /* private fields */ }
Expand description

The screen shell. A fluent builder finished by Scaffold::build.

Implementations§

Source§

impl<Msg: Clone + 'static> Scaffold<Msg>

Source

pub fn new() -> Self

Creates a shell for the surface it is being built for.

The size and the intrusions both come from MediaQuery::of: the application does not measure the screen, subtract the notch and the bars from it, and hand the remainder down: it says Scaffold::new() and the shell keeps its own slots clear of whatever the platform reported. That is the reference’s arrangement, where Scaffold reads MediaQuery.of(context) and takes no size at all.

Outside any surface description — a unit test building a shell on its own — the size is zero, and Scaffold::size is how a test says how big the screen is. Wrapping the build in MediaQuery::new(size).scope(..) says it once for everything inside, which is usually what a test wants.

The navigation is a bottom bar whatever the width; ask for Scaffold::nav_placement to have it anywhere else.

Source

pub fn size(self, width: f32, height: f32) -> Self

The surface’s size, in logical pixels — an override.

Scaffold::new already takes it from MediaQuery::of. This is for the two cases that are not the whole screen: a shell laid into a sub-region of one, and a test that would rather state a size than install a description for it.

Source

pub fn insets(self, insets: Insets) -> Self

The permanent safe area (system bars, notch): the Scaffold keeps the slots clear of it.

This is the padding half of WindowInsets. To let the Scaffold lift its content off the soft keyboard as well, give it both halves with Scaffold::window_insets.

Source

pub fn window_insets(self, insets: WindowInsets) -> Self

The window insets, both kinds: the permanent padding and the transient area the keyboard covers.

The two are kept apart because only one of them may be ignored: Scaffold::resize_to_avoid_bottom_inset decides whether the keyboard pushes the content up, and no setting lets content sit under the navigation bar.

Source

pub fn resize_to_avoid_bottom_inset(self, resize: bool) -> Self

Whether the body is lifted clear of the soft keyboard (true by default).

Set it to false when the screen would rather be covered than shortened — a full-bleed image or a map, where losing half the height is worse than losing the bottom of it. The permanent insets are unaffected: content never goes under the navigation bar.

Source

pub fn extend_body(self, extend: bool) -> Self

Lets the body run under the bottom bar and the persistent footer rather than stopping above them.

For a bar that is translucent or notched, so that what scrolls past is seen through it. The body’s own content then needs bottom padding of its own, or its last row hides behind the bar.

Source

pub fn extend_body_behind_app_bar(self, extend: bool) -> Self

Lets the body run under the app bar, its top aligned with the top of the screen rather than with the bottom of the bar.

For a translucent bar over an image or a hero header. Same warning as Scaffold::extend_body: the content behind the bar is the body’s business.

Source

pub fn background(self, color: Color) -> Self

Background color, spread edge to edge, including under the system bars.

Source

pub fn app_bar(self, widget: impl Widget<Msg> + 'static) -> Self

The application bar, pinned at the top.

Source

pub fn body(self, widget: impl Widget<Msg> + 'static) -> Self

The screen’s body: it is given exactly the space between the bars, as the reference’s is, and takes what it wants of it (milestone 590).

It does not scroll. A body that may be taller than the room it is given goes inside a scrolling widget the screen chooses — SingleChildScrollView for a page that occasionally overflows, ListView for a long one — with no size of its own: an unsized scrolling widget is as big as the room.

ⓘ
.body(SingleChildScrollView::new().child(form))

A body that asks for nothing sits at the top of that room, at its own size; one that wants to be centred in it says Center.

The room includes the system’s intrusions when nothing else holds them off. With a bottom bar or a footer below it, they keep the body clear of the gesture bar; with neither, the body reaches the screen’s edge and is told the intrusion is there. A body whose content must not sit under it wraps in SafeArea:

ⓘ
.body(SafeArea::new(form))
Source

pub fn nav( self, selected: usize, on_select: impl Fn(usize) -> Msg + 'static, ) -> Self

Enables navigation: selected = the active destination, on_select(i) emitted on choice. Then add Scaffold::destinations.

The destinations go in a bottom bar unless Scaffold::nav_placement says otherwise.

Source

pub fn nav_placement(self, placement: NavPlacement) -> Self

Where the destinations are drawn: a bottom bar (the default) or a rail.

Fixed either way — the scaffold will not move the navigation because the window changed size. For that, use NavScaffold.

Source

pub fn nav_labels(self, labels: RailLabels) -> Self

When the destinations say what they are, whichever of the two widgets ends up carrying them. See RailLabels.

Unsaid, each keeps the default the reference gives it: a rail shows no labels, a bar shows them all (milestone 432).

Source

pub fn rail( self, configure: impl FnOnce(NavigationRail<Msg>) -> NavigationRail<Msg> + 'static, ) -> Self

What to do to the rail once the shell has built it from the destinations — .rail(|rail| rail.extended(true).group_alignment(0.0)).

The shell builds the navigation itself, which is what makes it a shell: an application says .destination("✔", "Tasks") and never sees the widget. That left everything a rail can do and a bar cannot — its extended form, where its destinations sit, the slots above and below them — reachable only by building the rail by hand and giving up the shell. This is the door: the shell builds the rail, hands it over, and takes back whatever comes out.

It runs last, after the destinations and after Self::nav_labels, so it has the final word on both. Silent when the navigation is a bottom bar, which has none of these properties to set.

The shell then measures the rail it was handed rather than assuming the width it started with — an extended rail is 256 wide, and everything the shell puts beside it has to know.

Source

pub fn destination( self, icon: impl Into<DestinationIcon>, label: impl Into<String>, ) -> Self

Adds a navigation destination (mark + label).

Source

pub fn destinations( self, destinations: impl IntoIterator<Item = NavigationDestination>, ) -> Self

Adds a whole list of destinations declared elsewhere — the same list a rail, a drawer or a NavScaffold would take, so an application describes its navigation once.

use frus_widgets::{Icons, NavigationDestination, Scaffold};

let places = vec![
    NavigationDestination::new(Icons::FAVORITE_BORDER, "Saved")
        .selected_icon(Icons::FAVORITE),
    NavigationDestination::new(Icons::MAIL_OUTLINE, "Inbox").badge(3),
];
let _shell = Scaffold::new()
    .body(frus_widgets::text("…"))
    .nav(0, |i| i)
    .destinations(places)
    .build();
Source

pub fn tooltip(self, message: impl Into<String>) -> Self

What a pointer resting on the last destination is told. See NavigationRail::tooltip.

Source

pub fn badge(self, count: u32) -> Self

A notification count on the last destination.

Source

pub fn selected_icon(self, icon: impl Into<DestinationIcon>) -> Self

The glyph the last destination shows while it is selected, where that differs from its resting one. See NavigationRail::selected_icon.

Source

pub fn disabled(self) -> Self

Marks the last destination inaccessible. See NavigationRail::disabled.

Source

pub fn indicator_color(self, color: Color) -> Self

The last destination’s own indicator colour, over the theme’s. See NavigationRail::indicator_color.

Source

pub fn drawer( self, panel: impl Widget<Msg> + 'static, open: bool, toggle: Msg, ) -> Self

A modal side drawer on the leading edge (left): panel = the content, open = expanded, toggle = the toggle message (the button, and a click on the scrim).

The usual home of the navigation on a phone. A screen may have this one and Scaffold::end_drawer at once — they are different drawers with different jobs, not a choice of side.

Source

pub fn end_drawer( self, panel: impl Widget<Msg> + 'static, open: bool, toggle: Msg, ) -> Self

A modal side drawer (right edge): panel = the content, open = expanded, toggle = the toggle message (the button, and a click on the scrim).

Source

pub fn fab(self, widget: impl Widget<Msg> + 'static) -> Self

A floating action button, anchored bottom-right, above the bottom bar.

It rides in a full-screen Stack layer over the shell. That layer does not swallow what is under it: only a widget that asks for clicks is registered as a target, so the transparent remainder of the layer is not one. (This carried an “experimental — intercepts the bottom half of the screen” warning for a long time; a test now says otherwise.)

Source

pub fn bottom_app_bar(self, bar: BottomAppBar<Msg>) -> Self

A bottom app bar in place of the navigation one: the actions belonging to the screen you are on, rather than a choice of screen.

Taken by its own type, not as an opaque widget, so that the scaffold can cut the bar’s notch once it knows where it is putting the FAB. A docked button and a bar that does not know about it would sit on top of each other.

A scaffold given both this and Scaffold::destinations keeps the navigation — being able to leave the screen outranks the actions on it.

Source

pub fn fab_location(self, location: FabLocation) -> Self

Where the FAB sits: which end of the row, and whether it floats clear of the bottom bar or docks astride its top edge. FabLocation::EndFloat by default.

Source

pub fn fab_size(self, size: f32) -> Self

The height the FAB is taken to have when it is docked, since that placement puts its centre on the bar’s edge and so has to know how tall it is. 56 px — the conventional diameter — unless said otherwise.

A declared number rather than a measured one, and that is a divergence worth naming: the scaffold is handed the button as an opaque widget it cannot measure. A button of another size docks correctly once it says so.

A strip pinned between the body and the bottom bar, always visible: the screen’s committing actions (Save, Cancel), which must not be scrolled away.

Unlike the FAB it is not an overlay — it takes its own height out of the body, which is the point: it is part of the screen, not floating over it.

How the persistent footer is aligned in its row (Justify::End by default, the conventional place for a confirming action).

Source

pub fn bottom_sheet( self, panel: impl Widget<Msg> + 'static, open: bool, toggle: Msg, ) -> Self

A modal sheet sliding up from the bottom.

Source

pub fn primary(self, primary: bool) -> Self

Whether the shell sits at the top of the screen, so that its app bar is the thing that absorbs the status bar. true by default.

false says something else is above it — a shell nested in a page, a second one beside the first — and the app bar then takes only its own height, with the top intrusion left to whatever is actually up there.

This is both halves of the reference’s switch. There, Scaffold.primary makes the slot tall enough and AppBar.primary is what actually pads, the bar wrapping itself in a SafeArea — a split that works because its slots are built lazily under a description the shell controls. Ours are handed a widget that is already built, so the shell insets the slot from outside and there is one switch, not two. Milestone 394 records what a builder-based slot would change about that.

The line along the top of the persistent footer. Drawn by default, as the reference draws it — its footer is a container decorated with a one-pixel top border unless the caller replaces the decoration.

The line is a Divider, so its colour and its thickness follow the theme like every other one, and a caller who wants neither says false.

The background behind the persistent footer. Unset, it is the shell’s own — the footer is part of the screen, not a bar laid on it.

Source

pub fn drawer_scrim_color(self, color: Color) -> Self

The scrim behind an open drawer, alpha included: the transparency of a scrim is its colour, so Color::TRANSPARENT darkens nothing and an opaque value hides the screen behind it.

Both drawers take it, as the reference’s single drawerScrimColor does.

Source

pub fn drawer_barrier_dismissible(self, dismissible: bool) -> Self

Whether a click on the scrim closes the drawer. true by default, and the reference’s drawerBarrierDismissible is the same switch.

false is for a drawer holding something that must be answered — the way out is then a control inside the panel, and the screen behind stays unreachable.

Source

pub fn build(self) -> Box<dyn Widget<Msg>>

Assembles the shell into a widget ready to display.

Trait Implementations§

Source§

impl<Msg: Clone + 'static> Default for Scaffold<Msg>

Source§

fn default() -> Self

The same as Scaffold::new — a shell for the surface being built for, with every slot empty.

Auto Trait Implementations§

§

impl<Msg = Callback> !RefUnwindSafe for Scaffold<Msg>

§

impl<Msg = Callback> !Send for Scaffold<Msg>

§

impl<Msg = Callback> !Sync for Scaffold<Msg>

§

impl<Msg = Callback> !UnwindSafe for Scaffold<Msg>

§

impl<Msg> Freeze for Scaffold<Msg>
where Option<Box<dyn Widget<Msg>>>: Freeze, Option<Box<dyn Fn(usize) -> Msg>>: Freeze, Option<Box<dyn FnOnce(NavigationRail<Msg>) -> NavigationRail<Msg>>>: Freeze, Option<(Box<dyn Widget<Msg>>, bool, Msg)>: Freeze, Option<BottomAppBar<Msg>>: Freeze,

§

impl<Msg> Unpin for Scaffold<Msg>
where Option<Box<dyn Widget<Msg>>>: Unpin, Option<Box<dyn Fn(usize) -> Msg>>: Unpin, Option<Box<dyn FnOnce(NavigationRail<Msg>) -> NavigationRail<Msg>>>: Unpin, Option<(Box<dyn Widget<Msg>>, bool, Msg)>: Unpin, Option<BottomAppBar<Msg>>: Unpin,

§

impl<Msg> UnsafeUnpin for Scaffold<Msg>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<Msg> IntoMsg<Msg> for Msg

Source§

fn defer(work: impl Fn() -> Msg + 'static) -> Msg

The message that stands for work’s result.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.