pub fn for_each_items<T: Clone + 'static, V: IntoView>(
items: &[T],
builder: impl Fn(&T) -> V + 'static,
) -> ViewExpand 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?
More 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}