1

I have built a Chips Container based on this link. Basically is just a container that orders chips in rows. This is my code:

struct ChipsContent: View {
    @ObservedObject var viewModel = ChipsViewModel()
    @State private var totalHeight
              = CGFloat.zero
    
    var body: some View {
        var width = CGFloat.zero
        var height = CGFloat.zero
        return ScrollView {
            GeometryReader { geo in
                    ZStack(alignment: .topLeading, content: {
                    ForEach(viewModel.dataObject) { chipsData in
                        Chips(systemImage: chipsData.systemImage,
                              titleKey: chipsData.titleKey,
                              isSelected: chipsData.isSelected)
                            .padding(.all, 5)
                            .alignmentGuide(.leading) { dimension in
                                if (abs(width - dimension.width) > geo.size.width) {
                                    width = 0
                                    height -= dimension.height
                                }
                                
                                let result = width
                                if chipsData.id == viewModel.dataObject.last!.id {
                                    width = 0
                                } else {
                                    width -= dimension.width
                                }
                                return result
                              }
                            .alignmentGuide(.top) { dimension in
                                let result = height
                                if chipsData.id == viewModel.dataObject.last!.id {
                                    height = 0
                                }
                                return result
                            }
                    }
                    }).background(viewHeightReader($totalHeight))
            }.padding(.all, 5)
        }.frame(height: height)
    }
    
    private func viewHeightReader(_ binding: Binding<CGFloat>) -> some View {
            return GeometryReader { geometry -> Color in
                let rect = geometry.frame(in: .local)
                DispatchQueue.main.async {
                    binding.wrappedValue = rect.size.height
                }
                return .clear
            }
        }
}

With this code, the container gets the height according to its content. I want to set a max-height to the Scroll view and if the content is greater than this max height the content should be scrollable. Is it possible to do that?

Dani Garcia
  • 464
  • 1
  • 6
  • 18

1 Answers1

2

Use .frame(minHeight: …, maxHeight: …)

By setting minimum and maximum heights you are limiting the freedom of SwiftUI to decide about the size, so you have more control versus just mentioning .frame(height: …), which is treated as a recommendation but not a value that must be adhered to.

shim
  • 9,289
  • 12
  • 69
  • 108
Guy Nir
  • 1,098
  • 9
  • 7
  • The [documentation](https://developer.apple.com/documentation/swiftui/view/frame(width:height:alignment:)) doesn't really support this notion that `.frame(height: …)` is treated as a recommendation. Where is that from? – shim Jul 21 '22 at 19:30
  • You are right about the documentation, using .frame(height: …) should mention the fix size. But at least from my experience, it does not work this way. Maybe they will fix it or already did. – Guy Nir Sep 29 '22 at 09:13
  • I assume that it tries to respect the fixed size, but like autolayout it will break the sizes if it has to to resolve conflicts. – shim Oct 03 '22 at 21:15