I would like to have a wrapped list of tags for each row in a SwiftUI list which I imagine to be the equivalent of a CSS float: left
(e.g. using this or this in each row of a swiftUI view). However, anytime I have a solution with a GeometryReader in it and I combine it with a @Binding
variable on an array that changes count I get a runtime failure when that bound count changes, though only after I navigate back to the list view from the detail view (see example below). According to this there are known issues with using a GeometryReader inside the row of a List in some scenarios, but if that's the case how can I achieve my goal of having a dynamic list where each row has it's own dynamic, wrapped list of tags?
- Note 1: there are no errors if I just use a simple HStack or LazyVGrid without a GeometryReader, but then these solutions either don't wrap at all or don't wrap nicely (a grid is not the same as
float: left
). - Note 2: there are no errors with changing an existing tag even with a wrapping GeometryReader stack so long as the count of the array of items in it does not change (see comments in below example).
For example, given the following:
struct Item {
let id = UUID()
var tags: [String]
}
struct Parent: View {
@Binding var items: [Item]
var body: some View {
List {
ForEach($items, id: \.id) { $item in
NavigationLink(destination: DetailView($item)) {
<View with GeometryReader in it Binding to $items.tags. See two examples below for two ways to try this. Each example replaces this tag.>
}
}
}
}
}
struct DetailView: View {
@Binding var item: Item
var body: some View {
List {
ForEach($item.tags, id: \.self) { $tag in
// When the following is edited, after navigating back there is no problem
// and the parent list view updates with the edited as expected.
TextField("Tag...", text: $tag)
}
// When the following is edited, after navigating back there *IS* a problem
// and the parent list view crashes with the errors mentioned below.
Button("Add tag") {
item.tags.append("")
}
}
}
}
I've gotten a different errors depending on what GeometryReader solution I'm using to replace <View with GeometryReader... Each example replaces this tag.>
, but all solutions fail, and a few of the errors are as follows (where WrappedHStack
and TagCloudView
are wrapping around GeometryReader).
SwiftUI/UpdateCoalescingTableView.swift:365: Fatal error: List update took more than 1 layout cycle to converge
which corresponds to replacing the above tag with (from this):
import WrappingStack
WrappingHStack(id: \.self, alignment: .topTrailing, horizontalSpacing: 8, verticalSpacing: 8) {
ForEach($item.tags, id: \.self) { tag in
Text(tag)
}
}
[error] precondition failure: attribute failed to set an initial value: 598072, ForEachChild<Array<String>, String, ModifiedContent<ModifiedContent<ModifiedContent<ModifiedContent<ModifiedContent<ModifiedContent<ModifiedContent<ModifiedContent<Text, _PaddingLayout>, _EnvironmentKeyWritingModifier<Optional<Font>>>, _BackgroundStyleModifier<Color>>, _EnvironmentKeyWritingModifier<Optional<Color>>>, _ClipEffect<RoundedRectangle>>, _PaddingLayout>, _AlignmentWritingModifier>, _AlignmentWritingModifier>>
which corresponds to replacing the above tag with (from this):
TagCloudView(tags: $item.tags.wrappedValue.map{ $0.tag })