Skip to main content

for_each_items

Function for_each_items 

Source
pub fn for_each_items<T: Clone + 'static, V: IntoView>(
    items: &[T],
    builder: impl Fn(&T) -> V + 'static,
) -> View
Expand description

GeometryReader { … } ForEach over a Rust collection.

The common case, and the one for_each makes awkward: with only a range, a caller writes for_each(0..items.len() as i64, …) and indexes back into the slice, which is the loop SwiftUI was supposed to be writing.

Identity is still positional — this builds on ForEach(0..<count), so inserting in the middle makes SwiftUI treat every later row as changed rather than moved, exactly as the Swift spelling would.

Examples found in repository?
examples/inbox.rs (line 114)
110fn body() -> View {
111    let i = inbox();
112    let rows = matching();
113    navigation_stack(
114        list(for_each_items(&rows, |&i| linked_row(i)))
115        .list_style(views::ListStyle::InsetListStyle)
116        .searchable(&i.query, &i.searching, SearchFieldPlacement::Automatic, "Search"),
117    )
118    .navigation_title("Inbox")
119    .toolbar(button("Compose", || {}).keyboard_shortcut(KeyboardShortcut::DefaultAction))
120}
More examples
Hide additional examples
examples/sugar.rs (line 24)
4fn main() {
5    let show_detail = true;
6    let items = vec![String::from("alpha"), String::from("beta")];
7
8    let sugared = swiftui! {
9        VStack(spacing: 8.0) {
10            Text("Title").text_style(.large_title)
11            if show_detail {
12                Text("the details")
13            }
14            ForEach(items) { item in
15                Text(item)
16            }
17        }
18    };
19
20    let by_hand = vstack_spacing(
21        &[
22            text("Title").text_style(views::TextStyle::LargeTitle),
23            conditional(show_detail, text("the details"), empty()),
24            for_each_items(&items, |item| text(item)),
25        ],
26        8.0,
27    );
28
29    let a = views::dump_value_to_depth(&sugared.into_handle(), 6);
30    let b = views::dump_value_to_depth(&by_hand.into_handle(), 6);
31    eprintln!("macro == hand-written? {}", a == b);
32    if a != b {
33        for (x, y) in a.lines().zip(b.lines()) {
34            if x != y {
35                eprintln!("  macro: {}\n  hand : {}", x.trim(), y.trim());
36                break;
37            }
38        }
39    }
40}
examples/todo.rs (lines 118-121)
83fn body() -> View {
84    let todos = items().lock().unwrap().clone();
85    let remaining = todos.iter().filter(|i| !i.done).count();
86
87    vstack_aligned_spacing(
88        &[
89            hstack![
90                text("Todo").text_style(TextStyle::LargeTitle).bold(),
91                spacer(),
92                text!("{remaining} left").fg_system(SystemColor::Gray),
93            ],
94            hstack_spacing(
95                &[
96                    textfield_bound("What needs doing?", draft())
97                        .text_field_style(views::TextFieldStyle::RoundedBorderTextFieldStyle)
98                        .on_submit(SubmitTrigger::Text, add)
99                        .submit_label(SubmitLabel::Done),
100                    button("Add", add).button_style(views::ButtonStyle::BorderedProminent),
101                ],
102                8.0,
103            ),
104            // The empty state is a branch, so it arrives and leaves rather than
105            // appearing from nothing.
106            view_if!(
107                todos.is_empty(),
108                vstack_spacing(
109                    &[
110                        system_image("checkmark.seal").view().font_size(40.0)
111                            .fg_system(SystemColor::Green),
112                        text("Nothing left to do").fg_system(SystemColor::Gray),
113                    ],
114                    8.0,
115                )
116                .frame_optional(None, Some(160.0), Alignment::Center)
117                .transition(Transition::ScaleWithOpacity { scale: 0.8, anchor: (0.5, 0.5) }),
118                list(for_each_items(
119                    &todos.iter().cloned().enumerate().collect::<Vec<_>>(),
120                    |(i, it)| row(*i, it),
121                ))
122                .list_style(views::ListStyle::PlainListStyle)
123            ),
124        ],
125        HorizontalAlignment::Leading,
126        Some(14.0),
127    )
128    .padding(20.0)
129}