swiftui

A Grid inside a DisclosureGroup inside a ScrollView causes unwanted expansion


As seen in the screenshots below, having a Grid inside the DisclosureGroup causes resizing. I've tried replacing the Grid with a set of VStack and HStack layouts and that has no expansion problem. (In the original app, that didn't give me the layout control I needed to match Grid.)

Depending on the phone screen size, this may make the chevrons move completely off-screen.

You don't have to build and run - the problem can be seen in the XCode Canvas preview of the view. Full sample on GitHub.

Cut-down from a much more complex sample to get a minimal reproducible case where the bump in size is obvious. Note that the two nested DisclosureGroups is not a factor - the jump in sizing occurs still if the outer one is removed but it's harder to see.

Whilst experimenting further, I found that removing the outer ScrollView fixes it but that is not a viable fix.

Problem reproduced on:


import SwiftUI

struct ContentView: View {

    @AppStorage("controlsExpanded") private var controlsExpanded: Bool = true
    @AppStorage("formattingExpanded") private var formattingExpanded: Bool = true
    @State private var stepperWidth: CGFloat = 40  // To store the measured width of the stepper
    @ScaledMetric var controlSpacing: CGFloat = 12.0

    // fake states instead of original doc
    @State private var useSpaces = true
    @State private var sampleText = """
    I wish that I could always see
    my code as lovely as a tree
    in subtle breeze, with sunlight wove
    a symphony, across the grove.

    Yet ugly leaks and bugs do mar
    ambitious grace - squint from afar.
    The bramble hell of versioned phones
    stabs and tangles, then hides my bones.
    """
    
    var body: some View {
        ScrollView {
            VStack {
                DisclosureGroup("Export settings", isExpanded: $controlsExpanded) {
                    
                    VStack(alignment: .leading, spacing: controlSpacing) {
                        Spacer()
                        DisclosureGroup("Formatting", isExpanded: $formattingExpanded) {
                            Grid(alignment: .leading, verticalSpacing: controlSpacing) {
                                GridRow {
                                    Text("Indent with spaces")
                                    Spacer()
                                    Toggle("", isOn: $useSpaces)
                                    .gridColumnAlignment(.trailing)
                                }
                            } // Grid
                            .padding(.horizontal)
                        }  // Formatting group
                        .padding(.horizontal, 4)
                    }
                }  // disclosure
                Spacer()
                    .frame(height: 40.0)
                Rectangle()
                    .frame(maxWidth: .infinity, maxHeight: 2.0)
                
                Spacer()
                    .frame(height: 20.0)
                Text(sampleText)  // dependency implied on dirty flag from changing emitter params
                    .textSelection(.enabled)
            } // outer VStack
            .padding()
        }  // scroll
    }
}

Combined screenshots showing expansion


Solution

  • Removing the Spacer in the grid fixes the problem.

    GridRow {
        Text("Indent with spaces")
        Toggle("", isOn: $useSpaces)
            .gridColumnAlignment(.trailing)
    }