How to remove the left and right Padding of a List in SwiftUI?
It looks like .listRowInsets
doesn't work for rows in a List
that is initialised with content
.
So this doesn't work:
List(items) { item in
ItemRow(item: item)
.listRowInsets(EdgeInsets())
}
But this does:
List {
ForEach(items) { item in
ItemRow(item: item)
.listRowInsets(EdgeInsets())
}
}
Remove top padding from `List` in SwiftUI
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
.
Remove default padding from List in SwiftUI
To achieve this you need to use ForEach
inside List
combined with .listRowInsets
as in example below
struct Demo: View {
var colors: [Color] = [.red, .blue, .yellow]
var body: some View {
List {
ForEach(colors, id: \.self) { color in
color
}.listRowInsets(EdgeInsets())
}
// Update: Different iOS versions have different
// default List styles, so set explicit one if needed
.listStyle(PlainListStyle())
}
}
backup
SwiftUI: remove the space on List view left and right?
So, I finally found a built in way of doing this without having to hard code numbers. I spent some time digging around the documentation and found this, listRowInsets
:
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
extension View {
/// Applies an inset to the rows in a list.
///
/// Use `listRowInsets(_:)` to change the default padding of the content of
/// list items.
///
/// In the example below, the `Flavor` enumeration provides content for list
/// items. The SwiftUI ``ForEach`` structure computes views for each element
/// of the `Flavor` enumeration and extracts the raw value of each of its
/// elements using the resulting text to create each list row item. The
/// `listRowInsets(_:)` modifier then changes the edge insets of each row
/// of the list according to the ``EdgeInsets`` provided:
///
/// struct ContentView: View {
/// enum Flavor: String, CaseIterable, Identifiable {
/// var id: String { self.rawValue }
/// case vanilla, chocolate, strawberry
/// }
///
/// var body: some View {
/// List {
/// ForEach(Flavor.allCases) {
/// Text($0.rawValue)
/// .listRowInsets(.init(top: 0,
/// leading: 25,
/// bottom: 0,
/// trailing: 0))
/// }
/// }
/// }
/// }
///
/// ![A screenshot showing a list with leading 25 point inset on each
/// row_x0013_.](SwiftUI-View-ListRowInsets.png)
///
/// - Parameter insets: The ``EdgeInsets`` to apply to the edges of the
/// view.
/// - Returns: A view that uses the given edge insets when used as a list
/// cell.
@inlinable public func listRowInsets(_ insets: EdgeInsets?) -> some View
}
So then changing my code to this:
var body: some View {
NavigationView {
List {
ForEach(sctions) { section in
Section(header: Text(section.name)
.border(Color(.red))
.listRowInsets(.init(top: 0,
leading: 0,
bottom: 0,
trailing: 0))) {
ForEach(section.items) { item in
Text("\(item.name)")
.listRowInsets(.init(top: 0,
leading: 0,
bottom: 0,
trailing: 0))
.border(Color(.green))
}
}
}
}
.listStyle(.plain)
.navigationBarTitle("Title")
}
}
Gives me this result:
Interestingly enough, listRowInsets
works on the "cell", but also on the section header, which I then got stuck on. I wanted the section header to also go to the edges and it was not originally.
Hope this helps somebody else.
Left and right padding (not leading and trailing) in SwiftUI
Use @Environment(\.layoutDirection)
to get the current layout direction (LTR or RTL) and use it to flip .leading
and .trailing
as needed.
Here’s a ViewModifier
that wraps all that conveniently:
enum NoFlipEdge {
case left, right
}
struct NoFlipPadding: ViewModifier {
let edge: NoFlipEdge
let length: CGFloat?
@Environment(\.layoutDirection) var layoutDirection
private var computedEdge: Edge.Set {
if layoutDirection == .rightToLeft {
return edge == .left ? .trailing : .leading
} else {
return edge == .left ? .leading : .trailing
}
}
func body(content: Content) -> some View {
content
.padding(computedEdge, length)
}
}
extension View {
func padding(_ edge: NoFlipEdge, _ length: CGFloat? = nil) -> some View {
self.modifier(NoFlipPadding(edge: edge, length: length))
}
}
Use it like you would the standard padding modifiers:
Text("Text")
.padding(.left, 10)
Related Topics
Instantiated Optional Variable Shows as Nil in Xcode Debugger
How to Create Usdz File Using Xcode Converter
Unexpected Non-Void Return Value in Void Function (Swift 2.0)
Creating Custom Tableview Cells in Swift
Segue and Button Programmatically Swift
Append Text or Data to Text File in Swift
How to Generate a Random Number in Swift Without Repeating the Previous Random Number
How to Get the Count of a Swift Enum
Dyld: Library Not Loaded: @Rpath/Libswift_Stdlib_Core.Dylib
Swift Protocol With "Where Self" Clause
Xcode 8/Swift 3: Simple Uipicker Code Not Working
Check Password String Strength Criteria in Swift