Skip to main content

divider

Function divider 

Source
pub fn divider() -> View
Expand description

Create a Divider.

Examples found in repository?
examples/inbox.rs (line 66)
60fn detail(i: usize) -> View {
61    let m = &MESSAGES[i];
62    vstack_aligned_spacing(
63        &[
64            text(m.subject).text_style(TextStyle::Title).bold(),
65            text!("From {}", m.from).fg_system(SystemColor::Gray),
66            divider(),
67            text("Body text would go here.").fg_system(SystemColor::Gray),
68            spacer(),
69        ],
70        HorizontalAlignment::Leading,
71        Some(12.0),
72    )
73    .padding(20.0)
74    .navigation_title(m.subject)
75}
More examples
Hide additional examples
examples/app.rs (line 22)
9fn main() {
10    run(|| {
11        vstack(&[
12            text("Hello from Rust! ๐Ÿฆ€")
13                .padding(12.0)
14                .bg(Color::BLUE)
15                .rounded(8.0)
16                .opacity(0.95),
17            spacer(),
18            hstack(&[
19                image("star.fill"),
20                text("No Swift compiler needed"),
21            ]),
22            divider(),
23            text("Pure dlsym + arm64 asm โ†’ SwiftUI")
24                .padding(8.0),
25        ])
26        .padding(40.0)
27        .into_handle()
28    });
29}
examples/scenes.rs (line 53)
48fn main_window() -> ViewHandle {
49    vstack(&[
50        text("A SwiftUI app, no Swift source")
51            .font_size(20.0)
52            .padding(8.0),
53        divider(),
54        text(&format!("count: {}", counter().get()))
55            .font_size(34.0)
56            .padding(12.0),
57        hstack(&[
58            button("โˆ’", || counter().set(counter().get() - 1)),
59            button("+", || counter().set(counter().get() + 1)),
60        ]),
61        spacer(),
62        text("โŒ˜, for Settings ยท the โ˜… in the menu bar has a menu")
63            .font_size(11.0)
64            .opacity(0.6),
65    ])
66    .padding(24.0)
67    .frame(420.0, 300.0)
68    .focused_scene_value(counter_focus_key(), counter().get())
69    .into_handle()
70}
71
72/// The focused-value key the window publishes its count under.
73///
74/// `.focusedSceneValue(\.key, value)` is how a window tells the commands above
75/// it what is selected. Both halves are synthesised at run time: the
76/// `FocusedValueKey` conformance *and* the `WritableKeyPath<FocusedValues, Int?>`
77/// โ€” `FocusedValues` exports no properties, so unlike `EnvironmentValues` there
78/// is no SwiftUI modifier holding a key path to borrow.
79///
80/// The menu cannot *read* it yet: that needs `@FocusedValue`, a `DynamicProperty`
81/// SwiftUI instantiates itself, which is a different mechanism from anything
82/// here. What this demonstrates is the publishing half, in a real app.
83fn counter_focus_key() -> &'static views::FocusKey {
84    static K: std::sync::OnceLock<views::FocusKey> = std::sync::OnceLock::new();
85    K.get_or_init(|| views::focus_key("sceneCounter"))
86}
87
88fn settings_pane() -> ViewHandle {
89    vstack(&[
90        text("Preferences").font_size(18.0),
91        divider(),
92        text("This pane is a `Settings` scene โ€” the one โŒ˜, opens."),
93        text(&format!("It sees the same state: {}", counter().get()))
94            .opacity(0.7),
95    ])
96    .padding(24.0)
97    .frame(360.0, 200.0)
98    .into_handle()
99}
100
101fn utility_window() -> ViewHandle {
102    vstack(&[
103        text("Utility").font_size(16.0),
104        text("A `Window`, not a `WindowGroup`: one of it, addressed by id.")
105            .opacity(0.7),
106    ])
107    .padding(20.0)
108    .frame(320.0, 140.0)
109    .into_handle()
110}
111
112fn menu_bar_item() -> ViewHandle {
113    vstack(&[
114        text(&format!("count: {}", counter().get())),
115        button("Reset", || counter().set(0)),
116    ])
117    .padding(10.0)
118    .into_handle()
119}
120
121/// The whole app, as one scene.
122///
123/// Built afresh every time SwiftUI reads `App.body`, which is what makes the
124/// numbers in it live rather than a snapshot taken at launch.
125///
126/// macOS only, and not by choice: `Settings`, `Window`, `MenuBarExtra` and the
127/// whole of `Commands` are `@available(iOS, unavailable)`. iOS gets
128/// [`ios_body`], which is the part of this that exists there.
129#[cfg(target_os = "macos")]
130fn body() -> SceneHandle {
131    scenes! {
132        window_group { main_window() }
133        settings { settings_pane() }
134        window("Utility", "utility") { utility_window() }
135        menu_bar_extra("Count", "star.fill") { menu_bar_item() }
136        commands {
137            // A menu of its own, beside File and Edit.
138            menu("Counter") {
139                vstack(&[
140                    button("Increment", || counter().set(counter().get() + 1)),
141                    button("Decrement", || counter().set(counter().get() - 1)),
142                    divider(),
143                    button("Reset", || counter().set(0)),
144                ])
145            }
146            // In place of the standard File โ–ธ New.
147            replacing(NewItem) { button("New Count", || counter().set(0)) }
148            // Added after the standard Help entry.
149            after(Help) {
150                button("About this Rust app", || {
151                    eprintln!("built with no Swift compiler in sight");
152                })
153            }
154        }
155    }
156}
examples/dashboard.rs (line 59)
54fn body() -> View {
55    vstack_aligned_spacing(
56        &[
57            text("System").text_style(TextStyle::LargeTitle).bold(),
58            grid(&[grid_row(&[tile(0), tile(1), tile(2)])]),
59            divider(),
60            // A gauge over the busiest reading, which is a different control
61            // from the rings and reads the same state.
62            vstack_aligned(
63                &[
64                    text("Busiest").font_size(12.0).fg_system(SystemColor::Gray),
65                    gauge(reading(1), 0.0, 1.0, text("Memory"))
66                        .gauge_style(views::GaugeStyle::AccessoryLinearCapacityGaugeStyle)
67                        .tint_system(SystemColor::Orange),
68                ],
69                HorizontalAlignment::Leading,
70            ),
71            spacer(),
72            button("Refresh", refresh)
73                .button_style(views::ButtonStyle::BorderedProminent)
74                .keyboard_shortcut(KeyboardShortcut::DefaultAction),
75        ],
76        HorizontalAlignment::Leading,
77        Some(16.0),
78    )
79    .padding(20.0)
80    // Animate whatever changed, rather than snapping to the new reading.
81    .animation(LOAD[0].load(Ordering::Relaxed) as i64)
82}
examples/hot_reload.rs (line 135)
117fn status(error: Option<&str>, generation: u64, micros: u64) -> View {
118    let slots = spec::slot_summary();
119    let slot_line = if slots.is_empty() {
120        String::new()
121    } else {
122        slots
123            .iter()
124            .map(|(k, v)| format!("{k}={v}"))
125            .collect::<Vec<_>>()
126            .join("  ")
127    };
128
129    // The error row is *always* present, empty when there is nothing wrong.
130    // An error that appears and disappears would otherwise reflow the screen
131    // above it on every save โ€” which looks exactly like the reloader having
132    // replaced the view, and makes "did the screen survive this?" impossible
133    // to answer by looking.
134    let rows = vec![
135        divider(),
136        hstack_spacing(
137            &[
138                circle_shape()
139                    .fill_system(if error.is_some() {
140                        SystemColor::Orange
141                    } else {
142                        SystemColor::Clear
143                    })
144                    .frame(8.0, 8.0),
145                text(error.unwrap_or(""))
146                    .font_size(11.0)
147                    .fg_system(SystemColor::Orange),
148                spacer(),
149            ],
150            6.0,
151        )
152        .padding(6.0)
153        .frame(348.0, 24.0),
154        hstack_spacing(
155            &[
156                circle_shape()
157                    .fill_system(if error.is_some() {
158                        SystemColor::Orange
159                    } else {
160                        SystemColor::Green
161                    })
162                    .frame(8.0, 8.0),
163                text(&format!("gen {generation}"))
164                    .font_size(11.0)
165                    .fg_system(SystemColor::Secondary),
166                // Microseconds below a millisecond: a reload of a short spec
167                // really is that fast, and "0.0 ms" reads as "not measured".
168                text(&if micros < 1000 {
169                    format!("{micros} \u{b5}s")
170                } else {
171                    format!("{:.1} ms", micros as f64 / 1000.0)
172                })
173                .font_size(11.0)
174                .fg_system(SystemColor::Secondary),
175                spacer(),
176                text(&slot_line).font_size(11.0).fg_system(SystemColor::Secondary),
177            ],
178            8.0,
179        )
180        .padding(6.0)
181        .frame(348.0, 24.0),
182    ];
183    vstack_spacing(&rows, 0.0)
184}
examples/common/spec.rs (line 529)
487fn node_view(node: &Node) -> Result<View, String> {
488    let spacing = node.f64_attr("spacing").unwrap_or(8.0);
489    let base = match node.name.as_str() {
490        "vstack" => {
491            let kids = children(node)?;
492            match node.attr("align") {
493                Some(a) => vstack_aligned_spacing(&kids, h_align(a, node.line)?, Some(spacing)),
494                None => vstack_spacing(&kids, spacing),
495            }
496        }
497        "hstack" => {
498            let kids = children(node)?;
499            match node.attr("align") {
500                Some(a) => hstack_aligned_spacing(&kids, v_align(a, node.line)?, Some(spacing)),
501                None => hstack_spacing(&kids, spacing),
502            }
503        }
504        "zstack" => zstack_aligned(&children(node)?, align(node.attr("align").unwrap_or("center"), node.line)?),
505        "text" => {
506            let s = node.value.as_deref().unwrap_or("");
507            let mut v = text(s);
508            if let Some(style) = node.attr("style") {
509                v = v.text_style(text_style(style, node.line)?);
510            }
511            if let Some(size) = node.f64_attr("size") {
512                v = v.font_size(size);
513            }
514            if node.flag("bold") {
515                v = v.bold();
516            }
517            if node.flag("italic") {
518                v = v.italic();
519            }
520            if let Some(c) = node.attr("color") {
521                v = match tint(c, node.line)? {
522                    Tint::System(sc) => v.fg_system(sc),
523                    Tint::Literal(lc) => v.fg(lc),
524                };
525            }
526            v
527        }
528        "spacer" => spacer(),
529        "divider" => divider(),
530        // The action is a no-op on purpose: a spec read from a file has nowhere
531        // to put behaviour, and pretending otherwise would be worse than a
532        // button that visibly does nothing. `hot_reload.rs` is where a spec
533        // gains behaviour, by being reloaded.
534        "button" => button(node.value.as_deref().unwrap_or("Button"), || {}),
535        "color" => color(parse_color(node.value.as_deref().unwrap_or("#808080"), node.line)?),
536        "image" => system_image(node.value.as_deref().unwrap_or("star")).into_view(),
537        "rect" => match node.attr("color") {
538            Some(c) => match tint(c, node.line)? {
539                Tint::System(sc) => rectangle_shape().fill_system(sc),
540                Tint::Literal(lc) => rectangle_shape().fill(lc),
541            },
542            None => rectangle_shape().into_view(),
543        },
544        "circle" => match node.attr("color") {
545            Some(c) => match tint(c, node.line)? {
546                Tint::System(sc) => circle_shape().fill_system(sc),
547                Tint::Literal(lc) => circle_shape().fill(lc),
548            },
549            None => circle_shape().into_view(),
550        },
551        "capsule" => match node.attr("color") {
552            Some(c) => match tint(c, node.line)? {
553                Tint::System(sc) => capsule_shape().fill_system(sc),
554                Tint::Literal(lc) => capsule_shape().fill(lc),
555            },
556            None => capsule_shape().into_view(),
557        },
558        "progress" => progress(
559            node.value.as_deref().and_then(|v| v.parse().ok()).unwrap_or(0.5),
560            node.f64_attr("total").unwrap_or(1.0),
561        ),
562        "gauge" => gauge(
563            node.value.as_deref().and_then(|v| v.parse().ok()).unwrap_or(0.5),
564            node.f64_attr("min").unwrap_or(0.0),
565            node.f64_attr("max").unwrap_or(1.0),
566            text(node.attr("label").unwrap_or("")),
567        ),
568        "group_box" => group_box(stack_children(node)?),
569        "list" => list(stack_children(node)?),
570        "scroll" => stack_children(node)?.scroll(),
571        "form" => form(stack_children(node)?),
572        // Every bound control needs an explicit `@name`.
573        //
574        // Inventing one โ€” from the line, or from position in the tree โ€” looks
575        // friendlier and is a trap: adding a line above a `toggle` would
576        // change its derived name, and the control would silently reset on the
577        // next reload. A name the file states is a name that survives the file
578        // being edited, which is the entire point of the slots.
579        "toggle" => toggle_bound(
580            node.value.as_deref().unwrap_or("Toggle"),
581            &flag_slot(&require_slot(node)?, node.flag("on")),
582        ),
583        "slider" => {
584            let lo = node.f64_attr("min").unwrap_or(0.0);
585            let hi = node.f64_attr("max").unwrap_or(1.0);
586            slider_bound(
587                &number_slot(&require_slot(node)?, node.f64_attr("value").unwrap_or(lo)),
588                lo,
589                hi,
590            )
591        }
592        "stepper" => stepper_bound(
593            node.value.as_deref().unwrap_or("Stepper"),
594            &number_slot(&require_slot(node)?, node.f64_attr("value").unwrap_or(0.0)),
595            node.f64_attr("min").unwrap_or(0.0),
596            node.f64_attr("max").unwrap_or(100.0),
597            node.f64_attr("step").unwrap_or(1.0),
598        ),
599        "field" => textfield_bound(
600            node.value.as_deref().unwrap_or(""),
601            &string_slot(&require_slot(node)?, node.attr("text").unwrap_or("")),
602        ),
603        "label" => label(
604            node.value.as_deref().unwrap_or(""),
605            node.attr("icon").unwrap_or("star"),
606        ),
607        other => {
608            return Err(format!(
609                "line {}: no view called `{other}`; try one of {}",
610                node.line,
611                NAMES.join(", ")
612            ))
613        }
614    };
615    decorate(base, node)
616}