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>
impl<Msg: Clone + 'static> Scaffold<Msg>
Sourcepub fn new() -> Self
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.
Sourcepub fn size(self, width: f32, height: f32) -> Self
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.
Sourcepub fn insets(self, insets: Insets) -> Self
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.
Sourcepub fn window_insets(self, insets: WindowInsets) -> Self
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.
Sourcepub fn resize_to_avoid_bottom_inset(self, resize: bool) -> Self
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.
Sourcepub fn extend_body(self, extend: bool) -> Self
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.
Sourcepub fn extend_body_behind_app_bar(self, extend: bool) -> Self
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.
Sourcepub fn background(self, color: Color) -> Self
pub fn background(self, color: Color) -> Self
Background color, spread edge to edge, including under the system bars.
Sourcepub fn app_bar(self, widget: impl Widget<Msg> + 'static) -> Self
pub fn app_bar(self, widget: impl Widget<Msg> + 'static) -> Self
The application bar, pinned at the top.
Sourcepub fn body(self, widget: impl Widget<Msg> + 'static) -> Self
pub fn body(self, widget: impl Widget<Msg> + 'static) -> Self
The screen’s body: it fills the space between the bars.
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:
.body(SingleChildScrollView::new().flex(1.0).child(form))Left plain, the body is positioned at the top of that room, so a body that
wants all of it says so — .flex(1.0), or a Flex that centres its content.
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))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.
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.
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).
Sourcepub fn rail(
self,
configure: impl FnOnce(NavigationRail<Msg>) -> NavigationRail<Msg> + 'static,
) -> Self
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.
Sourcepub fn destination(
self,
icon: impl Into<DestinationIcon>,
label: impl Into<String>,
) -> Self
pub fn destination( self, icon: impl Into<DestinationIcon>, label: impl Into<String>, ) -> Self
Adds a navigation destination (mark + label).
Sourcepub fn destinations(
self,
destinations: impl IntoIterator<Item = NavigationDestination>,
) -> Self
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();Sourcepub fn tooltip(self, message: impl Into<String>) -> Self
pub fn tooltip(self, message: impl Into<String>) -> Self
What a pointer resting on the last destination is told. See
NavigationRail::tooltip.
Sourcepub fn selected_icon(self, icon: impl Into<DestinationIcon>) -> Self
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.
Sourcepub fn disabled(self) -> Self
pub fn disabled(self) -> Self
Marks the last destination inaccessible. See NavigationRail::disabled.
Sourcepub fn indicator_color(self, color: Color) -> Self
pub fn indicator_color(self, color: Color) -> Self
The last destination’s own indicator colour, over the theme’s. See
NavigationRail::indicator_color.
Sourcepub fn drawer(
self,
panel: impl Widget<Msg> + 'static,
open: bool,
toggle: Msg,
) -> Self
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.
Sourcepub fn end_drawer(
self,
panel: impl Widget<Msg> + 'static,
open: bool,
toggle: Msg,
) -> Self
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).
Sourcepub fn fab(self, widget: impl Widget<Msg> + 'static) -> Self
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.)
Sourcepub fn bottom_app_bar(self, bar: BottomAppBar<Msg>) -> Self
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.
Sourcepub fn fab_location(self, location: FabLocation) -> Self
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.
Sourcepub fn fab_size(self, size: f32) -> Self
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).
Sourcepub fn bottom_sheet(
self,
panel: impl Widget<Msg> + 'static,
open: bool,
toggle: Msg,
) -> Self
pub fn bottom_sheet( self, panel: impl Widget<Msg> + 'static, open: bool, toggle: Msg, ) -> Self
A modal sheet sliding up from the bottom.
Sourcepub fn primary(self, primary: bool) -> Self
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.
Sourcepub fn drawer_scrim_color(self, color: Color) -> Self
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.
Sourcepub fn drawer_barrier_dismissible(self, dismissible: bool) -> Self
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.