Reputation: 1395
I've seen similar questions like this one here on Stack Overflow, but none of them have been able to answer my question.
I have created a List
, but I want to remove the padding space (marked with a red arrow) above the content in the List
. How can I remove it when using a GroupedListStyle
?
This is a List
within a VStack
within a NavigationView
that is displayed via fullscreenCover
:
var body: some View {
NavigationView {
VStack {
taskEventPicker
myList
}
.navigationBarTitle("Add Task", displayMode: .inline)
}
}
where taskEventPicker
is a segmented Picker
(boxed in green):
var taskEventPicker: some View {
Picker("Mode", selection: $selection) { /* ... */ }
.pickerStyle(SegmentedPickerStyle())
.padding()
}
and myList
is the form in question (boxed in yellow):
var myList: some View {
List { /* ... */ }
.listStyle(GroupedListStyle())
}
What I've Tried
UITableView.appearance().tableHeaderView
to an empty frameUITableView.appearance().contentInset.top = -35
listRowInsets
(this affects all list rows)Note: I'm looking for an answer that can apply to the GroupedListStyle
. I understand that this issue does not occur with PlainListStyle
. This padding issue also occurs with the default listStyle
.
Xcode version: 12.5
Upvotes: 44
Views: 37207
Reputation: 1
List {
Section(header: Spacer(minLength: -16)) {
ForEach(viewModel.filteredAccounts, id: \.id) { account in
}.listStyle(InsetGroupedListStyle())
.scrollContentBackground(.hidden)
.environment(\.defaultMinListHeaderHeight, 0)
you need to use these 2 modifiers together
Section(header: Spacer(minLength: -16)) {
.environment(\.defaultMinListHeaderHeight, 0)
Upvotes: 0
Reputation: 1839
The correct approach is to use:
List {
///...
}
.contentMargins(0, .top, .scrollContent)
Unfortunately, this api is iOS 17+ only.
Upvotes: 1
Reputation: 2432
If you are targeting iOS 17 or later, the recommended approach is to use the contentMargins
modifier. You can remove the vertical spacing like this:
List {
// ...
}
.contentMargins(.top, 0)
Upvotes: 20
Reputation: 1557
While some of the above suggestions do apply, in my case it was something else.
I had similar extra spacing that I couldn't get rid of, but it was caused by a .contentMargins(.top, 50) modifier that was following the .inspector sheet loading the view containing the List.
Upvotes: 0
Reputation: 3934
Took me a while to find a solution I was happy with. The issue is when using .navigationBarTitleDisplayMode(.inline)
it won't allow to have no header for the first section, so a header is added automatically with default listRowInsets
and defaultMinListHeaderHeight
.
To control the top spacing, there are two things:
Section
and no list edge insets.environment(\.defaultMinListHeaderHeight, 12)
with a value you're happy with. This will be your top padding.NavigationStack {
List {
Section {
Text("Row 1")
Text("Row 2")
Text("Row 3")
} header: {
Spacer(minLength: 0).listRowInsets(EdgeInsets())
}
}
.listStyle(.insetGrouped)
.environment(\.defaultMinListHeaderHeight, 0)
.navigationTitle("Title")
.navigationBarTitleDisplayMode(.inline)
}
Upvotes: 16
Reputation: 1064
In iOS 17, just set the toolbarTitleDisplayMode
to inline
like so:
var body: some View {
NavigationStack(path: $path) {
List {
// Your items here
}
.listStyle(.plain)
.toolbarTitleDisplayMode(.inline)
}
}
Upvotes: 0
Reputation: 33
You specifically mention it is not an option for you to use PlainListStyle
, which is understandable. However, are you simply looking for an alternative to PlainListStyle
that does not have the padded sides? If so, I'd recommend trying InsetListStyle
.
The fat header is a core feature of GroupedListStyle
. Generally if I have to hack my way out of a core feature of anything, it's a red flag. I think we'd have to know more about why GroupedListStyle
feels like the only option for you, but my gut feeling here is there is an easier, more out-of-the-box way, and it may be InsetListStyle
.
Upvotes: 1
Reputation: 281
There is another possible solution
List {...}
.onAppear {
UICollectionView.appearance().contentInset.top = -20
}
you can use this modifier in the list
Upvotes: 1
Reputation: 425
Add top padding for List and Spacer with minLength 0 for first Section Header
NavigationView {
List {
Section {
Text("My Header")
} header: {
Spacer(minLength: 0)
}
.listStyle(.grouped)
.padding(.top, -20)
}
.navigationBarTitleDisplayMode(.inline)
}
Upvotes: 0
Reputation: 277
Another option is to add
List { ... }.offset(x: 0, y: -30).edgesIgnoringSafeArea(.bottom)
to the List. Since you won't be able to scroll all the way up when using this add a Spacer(minLength: 30)
at the very bottom of the List.
Upvotes: 3
Reputation: 161
extension View {
/// Clear tableview and cell color
func tableClearColor() {
let tableHeaderView = UIView(frame: .zero)
tableHeaderView.frame.size.height = 0.5
UITableView.appearance().tableHeaderView = tableHeaderView
}
}
Upvotes: -1
Reputation: 57
The contentInsent
part of the accepted answer works perfectly fine unless for instance as in my case, at the end of a navigation stack you want to use it in some detail view containing a List
with navigationBarTitleDisplayMode
set to .inline
. When navigating back in the stack to a view using another List
with navigationBarTitleDisplayMode
set to .large
, the List
content and NavigationBar
interlace awfully. And they probably might as well do whatever the navigationBarTitleDisplayMode
is set to.
Switching to listStyle(.plain)
in my case isn't a feasable option, because then in the detail view, I loose the beautifully animated built-in transitions to and from List's EditMode
, that seem to exist only in the grouped listStyle
varieties.
Finally, after quite a few days of frustration I figured out that tableHeaderView
is the approach that works best for my problem - and of course, it works just as well to solve the original question. It's all in here ...:
... and in this sentence:
"When assigning a view to this property [i.e. tableHeaderView
], set the height of that view to a nonzero value"
So I do like:
List {
// bla bla bla
}
.listStyle(.grouped)
.onAppear {
let tableHeaderView = UIView(frame: .zero)
tableHeaderView.frame.size.height = 1
UITableView.appearance().tableHeaderView = tableHeaderView
}
It's as simple as that. Hope it might help you, too!
Upvotes: 4
Reputation: 11666
my 2 cents. I arrived here for the same reason.
take a look at: https://developer.apple.com/forums/thread/662544
it' seems the correct approach.
Upvotes: -1
Reputation: 4888
Firstly, I would say that GroupedListStyle
is working as intended.
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 say you have tried this, but it does work for me (Xcode 12.5.1):
List { ... }
.onAppear(perform: {
UITableView.appearance().contentInset.top = -35
})
You could also hide the list header, by using a ZStack
with the List at the bottom of the stack and the Picker
over the top. The Picker does have transparency, so you would also have to add an opaque view to act as background for the Picker
.
var body: some View {
NavigationView {
ZStack(alignment: .top) {
List { ... }
.listStyle(.grouped)
.padding(.top, 30)
Color.white
.frame(height: 65)
Picker { ... }
.pickerStyle(.segmented)
.padding()
}
.navigationBarTitle("Add Task", displayMode: .inline)
}
}
As far as I can see this just appears the same as PlainListStyle
would do, but I assume you have a particular reason for wanting to use GroupedListStyle
.
Upvotes: 34
Reputation: 5570
I had a similar setup where I had some views and a List in a VStack and I had an undesired space that appeared on the top of my List. In my case I needed to set the VStack spacing to 0 and that solved the issue because it was actually just spacing from the VStack.
VStack(spacing: 0) { ... }
Upvotes: 6
Reputation: 775
Give a header to the first section in your list: Section(header: Spacer(minLength: 0))
Disclaimer: this doesn't totally remove the top spacing, but it does yield the same result as the native Settings app.
Note: This worked for me on iOS 14.5
VStack {
List {
Section(header: Spacer(minLength: 0)) {
Text(verbatim: "First Section")
}
Section {
Text(verbatim: "Second Section")
}
}
.listStyle(GroupedListStyle())
}
Upvotes: 10