How does listSectionSpacing works in SwiftUI?

Hello,

I want to understand how listSectionSpacing with a custom CGFloat value works in SwiftUI.

According to the documentation, we can use different spacing between sections and If adjacent sections have different spacing value, the smaller value on the shared edge is used.

For example, if I have a:

  • Section A with a listSectionSpacing of 10
  • Section B with a listSectionSpacing of 200
  • Section C with a listSectionSpacing of 20
  • Section D with a listSectionSpacing of 0

I notice the spacing between the sections A+B and B+C is none of 10, 200 or 20. If the documentation is correct, shouldn't it be 10?

If I now have a:

  • Section A with a listSectionSpacing of 200
  • Section B with a listSectionSpacing of 200
  • Section C with a listSectionSpacing of 200
  • Section D with a listSectionSpacing of 0

I notice the spacing is never 200. Is the spacing capped?

Also, if I specify a header and footer, the spacing doesn't seem to be used at all. Thus the spacing is the same for all sections.

Is my understanding wrong and this API working as expected?

Or is that a bug in how the spacing is used?

I filed #FB13699952 few weeks ago.

Axel


struct ListSections: View {
    @State private var header: Bool = false
    @State private var footer: Bool = false
    
    private let sections: [ListSection] = [
        ListSection(position: "A", spacing: 200),
        ListSection(position: "B", spacing: 200),
        ListSection(position: "C", spacing: 200),
        ListSection(position: "D", spacing: 0)
    ]
    
    var body: some View {
        VStack {
            Toggle("Header", isOn: $header)
            Toggle("Footer", isOn: $footer)
        }
        .padding(.horizontal)
        
        List {
            ForEach(sections) { section in
                Section {
                    LabeledContent("Section \(section.position)", value: section.spacing.formatted())
                } header: {
                    if header {
                        Text("Header \(section.position)")
                            .background(.red.opacity(0.3))
                    }
                } footer: {
                    if footer {
                        Text("Footer \(section.position)")
                            .background(.green.opacity(0.3))
                    }
                }
                .listSectionSpacing(section.spacing)
            }
        }
    }
}

#Preview {
    ListSections()
}

Hi @alpennec ,

Please check out this other post I just answered, it's along the same lines. https://developer.apple.com/forums/thread/756515

.listSectionSpacing cannot be applied to each section individually, it should be applied to the List. That's why you're not seeing a difference in the spacing between the sections in your preview. If you apply it to the List, you'll see that it gives each section the same spacing. I recommend filing a feedback report for an enhancement request at https://feedbackassistant.apple.com, but see the above thread for my workaround.

Best,

Sydney

Thanks @DTS Engineer Sydney for answering.

The documentation in Xcode 16 clearly states that it's possible to apply different spacing.

It's probably new to iOS 18 (and other OSes), but it seems buggy unfortunately. Can you make sure the feedback I mentioned in my previous post (https://feedbackassistant.apple.com/feedback/13699952) will be taken into consideration?

Thanks for bringing that to my attention @alpennec !

Looks like you'll need to do .listSectionSpacing(.custom(100.0)) for example to use a custom number.

I just tested with .listSectionSpacing(.custom(100.0)) but I obtain the same result. Also, the document I shared before is displayed from the other constructor. So it seems there are two ways to specify the listSectionSpacing.

Let's see if my feedback is updated soon.

I tested this on an iPhone running iOS 18 with the following code and noticed that the only difference that you can make is by using a smaller value, or .listSectionSpacing(.compact)

struct ContentView: View {
    var body: some View {
        List {
            Section {
                Text("Test 1")
            }
            .listSectionSpacing(10.0) //try replacing this with .listSectionSpacing(.compact) and you'll also see a smaller spacing
            
            Section {
                Text("Test 2")
            }
            Section {
                Text("Test 3")
            }
            Section {
                Text("Test 4")
            }
            Section {
                Text("Test 5")
            }
            
            Section {
                Text("Test 6")
            }
            .listSectionSpacing(1.0)
            
            Section {
                Text("Test 7")
            }
        }
    }
}

I noticed with the more sections you have, the easier you can see the difference. When you apply the section spacing of 1.0 to section 6, you can see that Test 5, Test 6, and Test 7 are all grouped very closely together with almost no spacing. When there's fewer sections, it seems like nothing is happening.

Sorry for the misunderstanding with .custom, I thought you needed the .custom but it seems like it does work without it.

Nevertheless, this is definitely an odd behavior to me as well that you cannot use larger values so thanks for filing that bug report.

Thanks @DTS Engineer for exploring with me! Before posting my first question, I initially thought I found the value that was used between sections.

It seems that spacingBeforeN = min(spacing[n] / 2 + spacing[n-1]/2, 35.33) So this would mean the spacing is capped to a maximum value (the default spacing?). And the documentation is wrong (it's not the minimum spacing that is used).

But it does not explain how it works with header and/or footer. As previously shared, when I enable a header and/or footer, the spacing doesn't seem to be used.

ah yes, the issue with the headers/footers is a known issue. I've also filed a bug report about the documentation.

How does listSectionSpacing works in SwiftUI?
 
 
Q