swiftuiscrollviewdisclosuregroup

How to configure a DisclosureGroup inside ScrollView to allow more space for other views when Disclosure is contracted?


I have a situation that has been, approximately, reproduced in the code below.

TopView() shows some text with a min scale factor. BottomView() shows other text in a DisclosureGroup which is inside a Scrollview. The text in TopView() is getting compressed (due to the min scale factor). I would like for it to expand to full font when the disclosure group is not expanded and contract when the DisclosureGroup is expanded.

import SwiftUI

@main
struct MainApp: App {
  
  var body: some Scene {
    WindowGroup {
      VStack(spacing: 8) {
        TopView()
        BottomView()
      }
    }
  }
}

struct TopView: View {
  var body: some View {
    GeometryReader { geometry in
      VStack(spacing: 8) {
        ForEach(0 ..< 15) { int in
          Text("\(int)")
            .foregroundColor(.black)
            .font(.system(size: 75))
            .minimumScaleFactor(0.50)
            .background(int % 2 == 0 ? .green : .red)
            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
        }
        .padding(0)
      }
    }
//    .layoutPriority(1)
  }
}

struct BottomView: View {
  @State var isExpanded = true
  
  var body: some View {
    GeometryReader { geometry in
      ScrollView {
        DisclosureGroup("Sample disclosure", isExpanded: $isExpanded) {
          ForEach(21 ..< 40) { int in
            Text("\(int)")
              .foregroundColor(.black)
              .font(.system(size: 75))
              .minimumScaleFactor(0.5)
          }
        }
        .font(.title)
        .padding()
      }
    }
  }
}

Here's a screenshot with the disclosure expanded and the TopView() compressed. enter image description here

Here's a screenshot with the disclosure not expanded and the TopView() stays compressed. How can I configure the ScrollView/DisclosureGroup to move down when contracted so there's more space for TopView()? enter image description here


Solution

  • You could use the isExpanded property for that:

    struct BottomView: View {
        @State var isExpanded = true
        
        var body: some View {
            GeometryReader { geometry in
                ScrollView {
                    DisclosureGroup("Sample disclosure", isExpanded: $isExpanded) {
                        ForEach(21 ..< 40) { int in
                            Text("\(int)")
                                .foregroundColor(.black)
                                .font(.system(size: 75))
                                .minimumScaleFactor(0.5)
                        }
                    }
                    .font(.title)
                    .padding()
                    
                }
            }
            .frame(maxHeight: isExpanded ? .infinity : 50) // <-- Add this line to the GeometryReader
        }
    }
    

    In this way the BottomView will take about half the space of the screen when expanded, and when contracted it will go to the bottom of the screen leaving more space for other Views.