1

I'm trying to achieve the following layout with SwiftUI in iOS 14:

Scroll View Layout

I have an inner ScrollView with a couple of "cells" each of which has the same aspect ratio. This inner ScrollView scrolls its content horizontally and is part of a view tree that is nested within an outer ScrollView which scrolls vertically.

Now I want to size the cells in a fashion that I can fit 4 of them in a (visible) row.

The width of the inner ScrollView is determined by the upper view tree (i.e. it's set from outside), but it's not fixed (for example, its frame might have a maxWidth of 500 which would result in a width of 500 on an iPad, but a smaller width on an iPhone, depending on the screen size). So I cannot simply do some maths by passing the width minus some padding into the child view or something like that.

So in code, my question ist the following:

struct MyView: View {

    var body: some View {
        ScrollView(.vertical) {
            ScrollView(.horizontal) {
                HStack(spacing: 8) {
                    ForEach(1..<8) { index in
                        RoundedRectangle(cornerRadius: 8)
                            .fill(.blue)
                            .aspectRatio(1, contentMode: .fit)
                            .frame(width: availableWidth / 4) // ← Here ❓
                    }
                }
            }
            .frame(maxWidth: 500)
            .padding()
        }
    }
}

How do I get the availableWidth here (i.e. the width proposed to the HStack) so that I can size the "cells" (RoundedRectangles) as desired?

It seems like the only way to go is with GeometryReader, but if I use a geometry reader within a scroll view, it will cause the scroll view to expand unnecessarily because GeometryReader always returns the proposed size as its ideal size.

Mischa
  • 15,816
  • 8
  • 59
  • 117
  • 1
    However, a `GeometryReader` in the background to the `ScrollView` will not cause the scrollView to expand. The simplest means is from [Federico Zenetello](https://www.fivestars.blog/articles/swiftui-share-layout-information/). You can see the solution and a convenience func in [this answer](https://stackoverflow.com/a/71386156/7129318). – Yrb Sep 28 '22 at 23:50
  • Yes, but it doesn’t give me auto-sizing. So the ScrollView won’t adjust its height to the height of its content which is what I need. When applying a background or overlay modifier and using a GeometryReader in there, all the views inside won’t have any effect on the layout of the outer world, including the inner scroll view. – Mischa Sep 29 '22 at 00:18
  • You wanted the information on the proposed size. This is how you get that information. How you use that information to cause a resize in your other views to fit four in the visible portion of the `ScrollView` is up to you. You proposed the solution yourself in the first paragraph. – Yrb Sep 29 '22 at 00:23
  • Classic problem: The scroll view receives its width from the outer world (in a first step), but its height from the inner world (depending on the width via aspect ratios). – Mischa Sep 29 '22 at 00:23
  • Look into Layout, there are a couple of WWDC videos on the subject from this year – lorem ipsum Sep 29 '22 at 02:39
  • @Yrb: You're right. The idea was so obvious that I didn't see it. I'm now feeding the GeometryReader's `size.width` into a `@State` property on the view which in turn triggers another layout cycle and yields the desired result. – Mischa Sep 29 '22 at 17:29

0 Answers0