SwiftUI 4: Set list background color

In SwiftUI 3 we used the following code snippet to set the background color of a list.

struct ContentView: View {
    var body: some View {
        List {
            Text("Hello World!")
        }
        .onAppear {
            // Placed here for sample purposes, normally set globally
            UITableView.appearance().backgroundColor = .clear
        }
        .listStyle(.insetGrouped)
        .background(Color.red)
    }
}

This is not working anymore in SwiftUI 4 (FB10225556) as the List is not based on UITableView anymore. Any workaround ideas?

Post not yet marked as solved Up vote post of saibot Down vote post of saibot
7.8k views

Replies

Found this note in the lounge:

In general, you should not rely on implementation details of a framework (including SwiftUI) to achieve specific behaviors in your apps. The release notes did call out the change in implementation of List since we were aware of developers using UIKit methods to style their Lists in the past. This is a known limitation, but we realize this is a popular request, so rest assured we have noted the feedback here and in the SwiftUI lounge!

Hmm.

FYI: We found a way using Introspect (not sure if in any way legal). However, as Apple Engineers noted, we should not rely on implementation details of a framework. Unfortunately, we are now in the stupid situation of having done exactly that in the past and now having to find a workaround. Otherwise our app looks extremely broken...

extension View {
    @warn_unqualified_access
    @ViewBuilder
    func listBackgroundColor(_ color: Color) -> some View {
        introspectViewController { inspectSubView($0.view, backgroundColor: .init(color)) }
    }

    // MARK: Helper

    private func inspectSubView(_ view: UIView, backgroundColor: UIColor) {
        for subview in view.subviews {
            if NSStringFromClass(type(of: subview)).contains("UICollectionViewListLayoutSectionBackgroundColorDecorationView") {
                subview.backgroundColor = backgroundColor
                return
            }
            inspectSubView(subview, backgroundColor: backgroundColor)
        }
    }
} 

The approach presented above does not work reliably as the UICollectionViewListLayoutSectionBackgroundColorDecorationView will be re-rendered regardless and independently of the section content. Then the view modification will not be applied.

I found an answer here:

https://stackoverflow.com/questions/72649907/ios-16-swiftui-list-background

  • This solution removes the list row separtors.

  • Asperi updated the solution on GitHub. However, still would prefer the promised native solution.

Add a Comment

New in iOS 16 beta 3, two new modifiers!

You can use them to set a background colour for a list:

List {
    ...
}
.scrollContentBackground(Color.red) // using .red results in an error

or set a custom background view:

List {
    ...
}
.scrollContentBackground(.hidden)
.background {
    Image(systemName: "list.bullet")
        .resizable()
        .scaledToFit()
        .padding()
}
  • In beta 5, the first modifier seems to have been removed. Only the second solution will work. Note: you may have to use ignoresSafeArea(_:edges:) on the background colour/view for it to fill the entire screen.

Add a Comment

I had the same issue. Use UIScrollView instead of UITableView

Try this.

struct ContentView: View {
    var body: some View {
        List {
            ForEach(0..<1) {_ in
                Text("Hello World")
            }
            .listRowBackground(Color.red)
        }
        .listStyle(.insetGrouped)
    }
}