How to adjust the height of a Form to it's content

Hello toegetier,

i do have a Form

            VStack {
                Form {
                    Section(header: Text("Select Your Home Club")) {
                        Picker ("Club", selection: $club) {
                            if club == nil {
                                Text("select club").tag(Optional<String>(nil))
                            }
                            ForEach(model.clubs.sorted()) { arg in
                                HStack {
                                    if let logo = arg.clubLogoUrl {
                                        ImageView(url: logo, key: logo, width: 28, height: 28)
                                            .scaledToFit()
                                            .padding(.trailing)
                                    } else {
                                        Text("")
                                            .frame(width:28, height:28)
                                            .padding(.trailing)
                                    }
                                    Text(" \(arg.name)")
                                }.tag(Optional(arg.name))
                            }
                        }
                        .pickerStyle(.menu)
                    }
                    
                    Section(header: Text("Select Your Home Ballpark")) {
                        Picker ("Ballpark", selection: $stadium) {
                            if stadium == nil {
                                Text("select ballpark").tag(Optional<Ballpark>(nil))
                            }
                            ForEach(model.ballparks.sorted()) { arg in
                                Text(arg.name).tag(Optional(arg))
                            }
                        }
                        .pickerStyle(.menu)
                    }
                    .onChange(of: stadium, initial: true) {
                        self.homeBallpark = stadium?.name ?? ""
                        print("homeBallpark: \(homeBallpark)")
                    }
                }.border(Color.blue)
                //.frame(height: 225)
                    
                Spacer()

                MapView(poi: stadium)
                    .cornerRadius(10)
                    .padding(.all)
            }

as we all know, the Form takes all available vertical space. Without the .frame()-modifier, the result looks like:

What I want is, that the Map-View is shown below the form and that the form changes it’s height based on it’s content:

I can only achieve this result by adding a .frame-modifier with an explicit number for its height. But that’s absolutely not the way how it should work. This maybe works right now, but this is not the intended dynamical change of content by Swiftui.

Does anyone has experience with such a topic? how can I solve this issue?

Thanks and best regards

Peter

If you place a Form and a Map() view in a VStack, they will both compete for the most space they can get and in so doing will at the very least get 50% each. Essentially SwiftUI will apportion an equal share of the available space to each View.

If the Form has content that results in it needing more than 50% of the available then its content will scroll.

The behaviour you are seeing is normal unless you choose to limit the space available to the Form by using a .frame modifier.

Thanks for the explanation, Chris!

But I think is not good coding, when I have to set the frame height explicitly. Isn’t there a programmatic possibility to get the needed (=minimum) height of the complete form? geometry reader gives unluckily a too big height (the whole screen resp. 50% of the screen height, when the map is shown).

Tthx, Peter

Rather than use a Form, just use a VStack and arrange the Picker to suit.

Hello Chris,

I rebuild the GUI with just VStacks and the Map and faced two interesting phenomenons.

  1. The map influences the position of the 1st VStack. The top padding is much bigger than intended. Please see enclosed pictures and code snippet.
    2.) The dark mode defined by systemBackgroundColor behaves different than a standard view. The dark colors are differently compares to a standard form . Please see the screenshots included.

Works as designed, a bug or the problem sits in front of the screen?

Thx, Peter

pictures: VStack with or without map


systemcolors, dark mode


If I can make a suggestion that you code your Pickers this way, so that you will save some vertical space which gives your Map more room.

Example View

struct MapView: View {
    @State private var textEntry1 = ""
    @State private var textEntry2 = ""
    @State private var location = CLLocationCoordinate2D()
    @State private var locationName = ""
    @State private var position = MapCameraPosition.camera(MapCamera.init(centerCoordinate: CLLocationCoordinate2D(latitude: -31.953512, longitude: 115.857048), distance: 100000))

    var body: some View {
        VStack {
            VStack {

                HStack {
                    Text("Choose Home Club")
                    Spacer()
                    Picker("Data", selection: $textEntry1) {
                        Text("London").tag("London")
                        Text("Perth").tag("Perth")
                    }
                }
                HStack {
                    Text("Chose Home Ballpark")
                    Spacer()
                    Picker("Data", selection: $textEntry2) {
                        Text("London Mets").tag("London Mets")
                        Text("Perth Heat").tag("Perth Heat")
                    }
                }
                    Button(action: {
                        position = MapCameraPosition.camera(MapCamera.init(centerCoordinate: CLLocationCoordinate2D(latitude: 51.509865, longitude: -0.118092), distance: 100000))
                        location = CLLocationCoordinate2D(latitude: 51.509865, longitude: -0.118092)
                        locationName = "London"

                    }, label: {
                        Text("Change location")
                    })


            }
            Spacer()
            Map(position: $position) {
                Marker("\(locationName)", systemImage: "mappin", coordinate: location)

            }
            .clipShape(RoundedRectangle(cornerRadius: 15))
            .onAppear {
                location = CLLocationCoordinate2D(latitude: -31.953512, longitude: 115.857048)
                locationName = "Perth"
            }
        }
        .padding()
    }
}

#Preview {
    MapView()
}

Looks like this:

The second screen shot is after tapping Change location which is just to show that the map position can be changed.