1

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).

  1. 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)
  }
}
  1. [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 })
Ethan Kay
  • 657
  • 6
  • 24
  • 1
    You talk about problems with a `GeometryReader`, but you don't show it in your posted code. This needs a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example). – Yrb Dec 30 '21 at 16:00
  • I gave two examples (`WrappingHStack` and `TagCloudView`) each of which use GeometryReader and can be swapped in for the commented block as stated in the post, both are also linked in the post. It seemed counter productive to paste in the full source code from the other SO posts. Are you suggesting I should choose one and paste it in the main example block? I can do that, though it may make it less clear that this isn't library specific. Note that with either of those snippets pasted in this is the minimum reproducible example I could construct, which I believe meets the SO guidelines. – Ethan Kay Dec 30 '21 at 16:49
  • I've updated the `` to make it clearer hopefully – Ethan Kay Dec 30 '21 at 16:51
  • Geometry Reader inside a List or ScrollView is a known issue, you are probably better off creating your own using SwiftUI.Layout. In iOS 16 geometry reader has very few places where it should be used because there are so many issues. – lorem ipsum Mar 06 '23 at 12:25

0 Answers0