0

I wanted some extra space on the top of the list so I tried using Spacer within the list and added modifiers to it. However I am not seeing the height getting reduced further. Below is the code for my view.

CustomView:

import SwiftUI

struct CustomView: View {
    var body: some View {
        VStack {
            List {
                Spacer()
                    .frame(minHeight: 1, idealHeight: 1, maxHeight: 2)
                    .fixedSize().listRowBackground(Color.clear)
                
                UserLoginDetailsRowView().padding(.init(top: 0, leading: 5, bottom: 5, trailing: 5))
                
                ForEach(1..<2) { _ in
                    VStack(alignment: .leading) {
                        Text("App version").fixedSize(horizontal: false, vertical: true).font(.headline).foregroundColor(.white)
                        Text("1.1.0").fixedSize(horizontal: false, vertical: true).font(.subheadline).foregroundColor(.white)
                        Spacer()
                    }.padding(.bottom, 15)
                }.listRowBackground(Color.clear)
            }
        }.navigationBarTitle("Main Menu")
    }
}

UserLoginDetailsRowView code:

import SwiftUI

struct UserLoginDetailsRowView: View {
    var body: some View {
        GeometryReader { geometry in
            VStack(alignment: .center) {
                Spacer()
                Spacer()
                Text("User's full name").lineLimit(2).font(.headline)
                Text("Username").lineLimit(2).font(.subheadline)
                Spacer()
            }
            
            ZStack {
                Image("user-gray")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 30 , height: 30)
                    .offset(x: geometry.size.width / 2.8, y: -geometry.size.height/4)
            }
        }.frame(minHeight: 60.0)
    }
}

This is how it looks with this code:

enter image description here

Regardless of the changes I make to minHeight, idealHeight and maxHeight in Spacer() within CustomView the result remains the same. However I want half of the space of what it's currently showing. I even tried replacing Spacer() with VStack and setting a frame height modifier to it, but at minimum, I do always see this much of space. I want the space reduced to half.

If I remove the Spacer() from CustomView then the image on my custom row gets chopped off and looks something like this. How do I reduce the space to half of what it is now?

enter image description here

Adding playground source code:

import SwiftUI
import PlaygroundSupport

struct CustomView: View {
    var body: some View {
        VStack {
            Spacer().frame(minHeight: 25, idealHeight: 25, maxHeight: 30).fixedSize().listRowBackground(Color.clear)

            List {
                // Extra space for the top half of user icon within UserLoginDetailsRowView.
//                Spacer().frame(minHeight: 25, idealHeight: 25, maxHeight: 30).fixedSize().listRowBackground(Color.clear)
                UserLoginDetailsRowView().padding(.init(top: 0, leading: 5, bottom: 5, trailing: 5))
                
                ForEach(1..<2) { _ in
                    VStack(alignment: .leading) {
                        Text("App Version").fixedSize(horizontal: false, vertical: true).font(.headline).foregroundColor(.white)
                        Text("1.1.0").fixedSize(horizontal: false, vertical: true).font(.subheadline).foregroundColor(.white)
                        Spacer()
                    }.padding(.bottom, 15)
                }.listRowBackground(Color.clear)
            }
        }.navigationBarTitle("Back")
    }
}

struct UserLoginDetailsRowView: View {
    var body: some View {
        GeometryReader { geometry in
            VStack(alignment: .center) {
                Spacer()
                Spacer()
                Text("User's full name").lineLimit(2).font(.headline)
                Text("Username").lineLimit(2).font(.subheadline)
                Spacer()
            }
            
            ZStack {
                Image(systemName: "person.circle")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 22 , height: 22)
                    .offset(x: geometry.size.width / 2.8, y: -geometry.size.height/4)
            }
        }.frame(minHeight: 60.0)
    }
}

PlaygroundPage.current.setLiveView(CustomView())
tech_human
  • 6,592
  • 16
  • 65
  • 107

1 Answers1

0

Solution

The primary gap comes from the list style itself. if you apply .listStyle(PlainListStyle()) to the List it will reduce it to what you are looking for.

List { ... }.listStyle(PlainListStyle())

If you want to further reduce it and control it to the last pixel apply a .onAppear modifier to the list and set the content inset to your desired value.

List { .... }.onAppear(perform: {
                UITableView.appearance().contentInset.top = -60
            })

In the above code the value 60 is arbitrary in nature and you need to play around to get a value that fits your UI.

Explanation

The List default style adds a larger header which creates the spacing you were having issues with, this behaviour is similar to GroupedListStyle. From the documentation

On iOS, the grouped list style displays a larger header and footer than the plain style, which visually distances the members of different sections.

You can play around with other List Styles from the documentation to fit your needs better.

Full Playground Code - For .onAppear solution

import SwiftUI
import PlaygroundSupport

struct CustomView: View {
    var body: some View {
        VStack(alignment:.leading, spacing:0) {
            
            List {
                // Extra space for the top half of user icon within UserLoginDetailsRowView.
                Spacer().frame(minHeight: 1, idealHeight: 1, maxHeight: 2)
                              .fixedSize().listRowBackground(Color.clear)
                UserLoginDetailsRowView().padding(.init(top: 0, leading: 5, bottom: 5, trailing: 5))
                
                
                ForEach(1..<2) { _ in
                    VStack(alignment: .leading) {
                        Text("App Version").fixedSize(horizontal: false, vertical: true).font(.headline).foregroundColor(.white)
                        Text("1.1.0").fixedSize(horizontal: false, vertical: true).font(.subheadline).foregroundColor(.white)
                        Spacer()
                    }.padding(.bottom, 15)
                }.listRowBackground(Color.clear)
            }.onAppear(perform: {
                UITableView.appearance().contentInset.top = -60
            })
        }.navigationBarTitle("Back")
    }
}

struct UserLoginDetailsRowView: View {
    var body: some View {
        GeometryReader { geometry in
            VStack(alignment: .center) {
                Spacer()
                Spacer()
                Text("User's full name").lineLimit(2).font(.headline)
                Text("Username").lineLimit(2).font(.subheadline)
                Spacer()
            }
            
            ZStack {
                Image(systemName: "person.circle")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 22 , height: 22)
                    .offset(x: geometry.size.width / 2.8, y: -geometry.size.height/4)
            }
        }.frame(minHeight: 60.0)
    }
}

PlaygroundPage.current.setLiveView(CustomView())

Eagnir
  • 459
  • 3
  • 7
  • It does reduce the space but the user image looks chopped off. Similar to the 2nd image I posted in my question. This are the values for my spacer modifiers when I moved it outside the List. Spacer().frame(minHeight: 30, idealHeight: 30, maxHeight: 35).fixedSize().listRowBackground(Color.clear) – tech_human Jun 29 '22 at 17:00
  • Can you give me a playground source code which shows the issue? I can't replicate the issue in playground on my side. – Eagnir Jun 29 '22 at 17:12
  • I added playground source code to my question. When you run it, you will see the person icon gets chopped off if I add Spacer() outside of the list. If you comment out Spacer() outside the List and uncomment Spacer() inside the list, then the person icon is completely visible, but it also adds a lot of space on the top. My intention is have space on the top, but maybe half or less of what it is now. – tech_human Jun 29 '22 at 17:36