title: FlexBox in SwiftUI
body: <p>Good day.
  I am trying to release dynamic placement of elements based on their size. Works in an empty project, but sometimes does not show the entire text. And in a working project, a maximum of 2-3 elements are displayed. Maybe I'm on the wrong path. Please tell me in which direction to look.
  I thought to use UICollectionView and UIViewRepresentable but couldn't figure out exactly how. There were examples on the Internet, but there was a common grid and the columns had the same width. And I just need to pave elements of different widths all the space from left to right line by line.</p>
  <pre><code>struct CustomFlexBoxView&lt;Content&gt; : View where Content: View {
      let alignment: Alignment
      let spacing: CGFloat
      let content: [Content]
      @State private var sizeBody: CGSize? = nil
      @State private var sizeItems: [Int:CGSize] = [:]
      init(alignment: Alignment = .center, spacing: CGFloat = 0, content: [Content]) {
          self.spacing = spacing
          self.alignment = alignment
          self.content = content
      }
      var body: some View {
          GeometryReader { (geo) in
              if let sizeBody = self.sizeBody {
                  self.contentView(sizeBody: sizeBody)
              }
              else {
                  self.contentFirstView
                      .onAppear {
                          self.sizeBody = geo.frame(in: .global).size
                      }
              }
          }
      }
      private var contentFirstView: some View {
          let items = self.content
          return VStack(spacing: 0) {
              ForEach(0 ..&lt; items.count) { (index) in
                  HStack(spacing: 0) {
                      items[index]
                  }
                  .background(
                      GeometryReader { (geo) in
                          Color.clear.onAppear {
                              self.sizeItems[index] = geo.frame(in: .global).size
                          }
                      }
                  )
              }
          }
      }
      private func contentView(sizeBody: CGSize) -&gt; some View {
          let items = self.content
          var rowWidth: CGFloat = 0
          var rowItems: [Content] = []
          var rows: [AnyView] = []
          for index in 0 ..&lt; items.count {
              if let size = self.sizeItems[index] {
                  if rowWidth + size.width + self.spacing &lt;= sizeBody.width {
                      let addSpacing = (rowItems.isEmpty ? 0 : self.spacing)
                      rowItems.append(items[index])
                      rowWidth = rowWidth + size.width  + addSpacing
                  }
                  else {
                      if rowItems.isEmpty == false {
                          rows.append(
                              AnyView(
                                  self.createRow(items: rowItems)
                              )
                          )
                          rowWidth = 0
                          rowItems = []
                      }
                      rowWidth = size.width
                      rowItems = [ items[index] ]
                  }
              }
              else {
                  if rowItems.isEmpty == false {
                      rows.append(
                          AnyView(
                              self.createRow(items: rowItems)
                          )
                      )
                      rowWidth = 0
                      rowItems = []
                  }
                  rows.append(AnyView(items[index]))
              }
          }
          if rowItems.isEmpty == false {
              rows.append(
                  AnyView(
                      self.createRow(items: rowItems)
                  )
              )
              rowWidth = 0
              rowItems = []
          }
          return AnyView (
              VStack(alignment: self.alignment.horizontal, spacing: self.spacing) {
                  ForEach(0 ..&lt; rows.count) { ind in
                      rows[ind]
                  }
              }
          )
      }
      private func createRow(items: [Content]) -&gt; some View {
          HStack(alignment: self.alignment.vertical, spacing: self.spacing) { [items] in
              ForEach(0 ..&lt; items.count) { ind in
                  items[ind]
              }
          }
      }
  }
  </code></pre>
  <p>On an empty project everything works, in the working one the first 2-3 elements are displayed.:</p>
  <pre><code>struct ContentView: View {
      @State var data: [Int] = [
          113, 2, 2342343, 234, 234234234234324, 3,
          45345435345345, 545, 34, 4, 345345345, 45345, 5, 5
      ]
      var body: some View {
          ScrollView {
              CustomFlexBoxView(
                  alignment: .topLeading,
                  spacing: 10,
                  content: self.data.map { TestText(text: &quot;\($0)&quot;) }
              )
          }
          .padding()
      }
  }
  struct TestText : View {
      let text: String
      @State private var color: Bool = false
      var body: some View {
          Text(self.text)
              .lineLimit(1)
              .fixedSize()
              .background(self.color ? Color.orange : Color.gray)
              .foregroundColor(self.color ? Color.green : Color.black)
              .onTapGesture {
                  self.color.toggle()
              }
      }
  }
  </code></pre>
  <p><a href="https://i.stack.imgur.com/jeehQ.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/jeehQ.png" alt="enter image description here" /></a></p>
  <p>But if you add more elements, then for some reason the total size of the CustomFlexBoxView is not estimated correctly:</p>
  <pre><code>    var body: some View {
          ScrollView {
              Rectangle()
                  .fill(Color.orange)
                  .frame(maxWidth: .infinity, minHeight: 100)
              CustomFlexBoxView(
                  alignment: .topLeading,
                  spacing: 10,
                  content: self.data.map { TestText(text: &quot;\($0)&quot;) }
              )
              Rectangle()
                  .fill(Color.orange)
                  .frame(maxWidth: .infinity, minHeight: 100)
          }
          .padding()
      }
  </code></pre>
  <p><a href="https://i.stack.imgur.com/JHDzX.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/JHDzX.png" alt="enter image description here" /></a></p>