June 3, 2020

SwiftUI list remove padding(Left and Right)

SwiftUI list remove padding(Left and Right)

SwiftUI can be great, for specific tasks it makes getting things done a breeze, but for others, it works in unexpected ways. Removing padding from a list is one of those things that really does not make sense to me.

This is how I thought I could remove padding from a list:

import SwiftUI

struct ContentView: View {
    
    enum Flavor: String, CaseIterable, Identifiable {
        var id: String { self.rawValue }
        case vanilla, chocolate, strawberry
    }
    
    var body: some View {
        VStack {
            // What I would expect to work but doesn't
            List(Flavor.allCases, id: \.self) { flavour in
                Text(flavour.rawValue)
                    .listRowInsets(.init())
                    .border(Color.red, width: 1)
            }
        }
    }
}

This code is quite straight forward, and I expected it to work but as you can see from the below image, it doesn't:

In fact, nothing changed even when I tried the following:

.listRowInsets(.init(top: 0,
                     leading: -20,
                     bottom: 0,
                     trailing: 20))
Note: I am using some of the code from Apple's documentation which you can find here.

The main difference between my code and the code in the documentation is that I moved the .listRowInsets to the Text view because the example in the documentation didn't work either.

So, in this post we are going to look at two ways to remove the padding from a list, the first way is not the greatest way as it only removes the left(leading) padding, but the second way will remove the left(leading) and the right(trailing) padding.

Solution 1: Remove left(leading) padding

List {
    ForEach(Flavor.allCases, id: \.self) { flavour in
        Text(flavour.rawValue)
            .listRowInsets(.init())
            .border(Color.red, width: 1)
    }
}

The only thing that I done to get it to work was use a ForEach inside the list. The Text with its view modifiers are exactly the same as the example above where it didn't work.

The above code will produce the following list:

This is not too bad if you are only looking for the padding on the left(leading) to be removed. If you want the padding on the left(leading) and the right(trailing) to be removed, take a look at the next solution.

Solution 2: Remove left(leading) and right(trailing) padding

Now that we can remove the padding on the left, let's remove the padding on the right. Unfortunately it is not as straight forward as removing the left padding as we need to use GeometryReader to "remove" the right padding.

GeometryReader { geometry in
    List {
        ForEach(Flavor.allCases, id: \.self) { flavour in
            Text(flavour.rawValue)
                .frame(width: geometry.size.width,
                       alignment: .leading)
                .listRowInsets(.init())
                .border(Color.red, width: 1)
        }
    }
}

There are two major changes in the above code compared to Solution 1. Firstly we are using GeometryReader, this will allow us to get the size and position of our parent view, we will only be using the width.

Secondly we use the geometry from GeometryReader to set the Text view width. When we set the width we need to add .leading alignment too, unless you want the text to be centered.  

If I run this code I get the following output:

In the list view above we have removed the left and effectively removed the right padding by changing the width of the list item content, in this case the Text view.

Below is an image of all the different lists in one app to see the difference:

Conclusion

Even though all the above code is easy I wish Apple would make something that worked out of the box. SwiftUI has only been out for a year or so, so one has to expect that things still need a lot of work.

If you want to see the full source code, you can find it here.