How to create a SwiftUI List View with a large (all list) header view?

Viewed 27

I would like to create a List view in SwiftUI with has a large, header which has no paddings and extends into the safe area.

For example like in this screenshot:

enter image description here

Solving this in UIKit would not be problem. One could simply use the tableViewHeader of UITableView to achieve this. But how can this be done in SwiftUI using a List view?

While I found several examples on how to create section headers, I found nothing about a complete table header.

Of course one can simple add a subview to the list:

List {
    // Header
    Rectangle()
        .someStyling(...)

    // Items
    ForEach(myList, id: \.self) { element in
        Text(element)
    }
}

However, the same paddings, safe area insets, etc. which are applied to the list items are also applied to the header. Can this be avoided?

Or is List not necessary?

I took this screenshot from this YouTube tutorial video. Unfortunately the tutorial does not show exactly what I am looking for. Instead of using a List to show large data set, it simply uses a ScrollView holding a VStack with an Image view (= the header) + a ForEach loop for the items.

Coming from UIKit and UITableView I have my doubts, that this is a good idea. Creating thousands of UIViews in a loop and stacking them would result in terrible performance. UITableView on the other hands re-uses view to create a much better performance.

But is this also true for List vs. VStack in SwiftUI?

Or is ListView just the same as a VStack and creating a large number of subviews in a loop is no problem here (e.g. because SwiftUI always only creates/draws the visible views)?

1 Answers

The thing about SwiftUI creating only the visible views is only true for LazyVStack, not VStack.

For the header in the List, you can use .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)). However, there would still be some spacing left.

You can use .padding(.all, -20) on the List, but then you would need to revert the padding on all of its elements. It’s a long shot, but could be worth it.

Related