I'm looking for a way to remove top section padding in my SwiftUI List
With iOS 15, we can do UITableView.appearance().sectionHeaderTopPadding = 0
However, with iOS 16, List has been reimplemented with UICollectionView and I couldn't find a way to remove the section header top padding
Here is sample code
import SwiftUI
struct TaskRow: View {
var body: some View {
Text("Task data goes here")
}
}
struct HeaderText: View {
var text:String
var body: some View {
Text(text)
.font(.system(.title3))
.fontWeight(.bold)
.foregroundColor(.primary)
}
}
struct ListWithSections: View {
init() {
if #available(iOS 15.0, *) {
UITableView.appearance().sectionHeaderTopPadding = 0
} else {
// Fallback on earlier versions
}
}
var body: some View {
if #available(iOS 16.0, *) {
List {
Section(header: HeaderText(text: "Section 1")) {
TaskRow()
TaskRow()
TaskRow()
}
Section(header: HeaderText(text: "Section 2")) {
TaskRow()
TaskRow()
TaskRow()
}
}
.scrollContentBackground(.hidden)
.background(Color.gray)
.listStyle(.plain)
} else {
List {
Section(header: HeaderText(text: "Section 1")) {
TaskRow()
TaskRow()
TaskRow()
}
Section(header: HeaderText(text: "Section 2")) {
TaskRow()
TaskRow()
TaskRow()
}
}
.background(Color.gray)
.listStyle(.plain)
}
}
}
Images for comparing between iOS 16 and iOS 15
Any way we can achieve it with List Plain Style?
Update: Using ListRowInset as @Yrb suggested will give almost same UI. However when we scroll, we have minor difference
Here what scroll in ios15 looks like (what I want to achieve in ios16)
Here what scroll in ios16 looks like (with listRowInset as @Yrb suggested)
Thanks in advance.
Best regards.
CodePudding user response:
SwiftUI has had a native implementation of this since iOS 13, but no one talked about it because you could reach under and set the UITableView.appearance()
. What you are dealing with in SwiftUI is listRowInsets
and the padding that Apple adds to the section header. Essentially what you do is take control of all of the insets. This is a double edged sword as you now control it all, you can't just set one and leave the rest as a default.
One thing you will find is that the defaults have changed from iOS 15 to iOS 16, so you can't use the same numbers. In iOS 16, you will also need to set the defaultMinListHeaderHeight
in .environment
.
I also extracted your section to save the repetition.
struct ListSecHeaderHeightView: View {
var body: some View {
List {
Section(header: SectionView(text: "Section 1")) {
Text("TaskRow")
Text("TaskRow")
Text("TaskRow")
}
Section(header: SectionView(text: "Section 2")) {
Text("TaskRow")
Text("TaskRow")
Text("TaskRow")
}
}
.scrollContentBackground(.hidden)
.environment(\.defaultMinListHeaderHeight, 0) // Only necessary in iOS 16. For 15, use 30
.background(Color.gray)
.listStyle(.plain)
}
}
struct SectionView: View {
let text: String
var body: some View {
HStack {
Text(text)
.font(.system(.title3))
.fontWeight(.bold)
.foregroundColor(.primary)
}
// Set it here.
// iOS 15:
// The top goes to -8 to cancel out the padding.
// The leading goes to 16 as you had the section in line with the rows.
// iOS 16:
// The top goes to -20.
// The leading goes to 20 as you had the section in line with the rows.
.listRowInsets(EdgeInsets(top: -8, leading: 16, bottom: 0, trailing: 0))
}
}
Lastly, please post Minimum Reproducible Examples. We should be able to run your code as posted.
CodePudding user response:
Yes, we also had the same issue. The condition is that padding will appear in each section header of the list on the simulator of the Xcode14 build iOS16 version. On the iOS15 version, we solve this problem by setting UITableView.appearance().sectionHeaderTopPadding = 0
globally, but it does not take effect on iOS16. It may be because the List component of swiftui on iOS16 uses UIcollectionview.
Unfortunately, we have so far didn't solve the problem.