How do I modify the background color of a List in SwiftUI?

SwiftSwiftui

Swift Problem Overview


I'm trying to recreate an UI I built with UIKit in SwiftUI but I'm running into some minor issues.

I want the change the color of the List here, but no property seems to work as I expects. Sample code below:

struct ListView: View {
    @EnvironmentObject var listData: ListData

       var body: some View {
        NavigationView {
            List(listData.items) { item in
                ListItemCell(item: item)
            }
            .content.background(Color.yellow) // not sure what content is defined as here
            .background(Image("paper-3")) // this is the entire screen 
        }
    }
}

struct ListItemCell: View {
    let item: ListItem

    var body: some View {

        NavigationButton(destination: Text(item.name)) {
            Text("\(item.name) ........................................................................................................................................................................................................")
                .background(Color.red) // not the area I'm looking for
        }.background(Color.blue) // also not the area I'm looking for
    }
}

I want to change the WHITE area

Swift Solutions


Solution 1 - Swift

Ok, I found the solution for coloring the list rows:

struct TestRow: View {

    var body: some View {
        Text("This is a row!")
        .listRowBackground(Color.green)
    }
}

and then in body:

List {
    TestRow()
    TestRow()
    TestRow()
}

This works as I expect, but I have yet to find out how to then remove the dividing lines between the rows...

Solution 2 - Swift

This will set the background of the whole list to green:

init() {
   UITableView.appearance().separatorStyle = .none
   UITableViewCell.appearance().backgroundColor = .green
   UITableView.appearance().backgroundColor = .green
}

Solution 3 - Swift

enter image description here

struct ContentView: View {
    
    var strings = ["a", "b"]
    
    var body: some View {
        
        List {
            ForEach(strings, id: \.self) { string in
                Text(string)
            }.listRowBackground(Color.green)
        }
    }
}

Solution 4 - Swift

You can do it by changing UITableView's appearance.

UITableView.appearance().backgroundColor = UIColor.clear

just put this line in Appdelegate's didFinishLaunchingWithOptions method. In replace of UIColor.clear set whatever color you want to add in background color of list.

Solution 5 - Swift

Changing Background Color

As other have mentioned, changing the UITableView background will affect all other lists in your app.

However if you want different background colors you can set the default to clear, and set the background color in swiftui views like so:

List {
    Text("Item 1")
    Text("Item 2")
    Text("Item 3")
}
// Ignore safe area to take up whole screen
.background(Color.purple.ignoresSafeArea())
.onAppear {
    // Set the default to clear
    UITableView.appearance().backgroundColor = .clear
}

You probably want to set the tableview appearance earlier, such as in the SceneDelegate or root view like so:

// SceneDelegate
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
      
    
    guard let windowScene = scene as? UIWindowScene else {
        print("Returning because screne does not exist")
        return
            
    }
    
    // Set here    
    UITableView.appearance().backgroundColor = .clear
    let contentView = ContentView()
    let window = UIWindow(windowScene: windowScene)
    window.rootViewController = UIHostingController(rootView: contentView)
    self.window = window
    window.makeKeyAndVisible()
}


// Root App View
@main
struct ListBackgroundApp: App {
    
    init() {
        UITableView.appearance().backgroundColor = .clear
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

Working Background Color Change

Solution 6 - Swift

There is an argument: listRowBackground() in SwiftUI, but if you use List directly to iterate the data collection, it doesn't work.

Here is my workaround:

    List {
        // To make the background transparent, we have we use a ForEach as a wrapper
        ForEach(files) {file in
            Label(
                title: { Text(file.name ?? fileOptionalFiller).lineLimit(listRowTextLineLimit) },
                icon: { AppIcon.doc.foregroundColor(.primary) }
            )
        }
        .listRowBackground(Color.primary.colorInvert())
    }

Basically, listRowBackground() works if you use a ForEach inside List.

Solution 7 - Swift

I was able to get the whole list to change color by using colorMultiply(Color:). Just add this modifier to the end of the list view, and then the padding will push the table to the device edges. For example:

List {...}.colorMultiply(Color.green).padding(.top)

https://www.hackingwithswift.com/quick-start/swiftui/how-to-adjust-views-by-tinting-and-desaturating-and-more

Solution 8 - Swift

I do not know what is the connection but if you wrap the list with Form it is working.

Form {
     List(viewModel.currencyList, id: \.self) { currency in
        ItemView(item: currency)
     }
      .listRowBackground(Color("Primary"))
      .background(Color("Primary"))
}

Solution 9 - Swift

struct Details: View {

    var body: some View {
        Spacer().overlay(
            List {
                Text("Hello World!").font(.title2)
                    .listRowBackground(Color.clear)
                Text("Hello World again").font(.title2)
                    .listRowBackground(Color.clear)
            }.onAppear() {
                UITableView.appearance().backgroundColor = UIColor.green
                UITableViewCell.appearance().backgroundColor = UIColor.green
            }
        )
    }
}

Solution 10 - Swift

2022, Solution for MacOS

the following code makes ALL OF Lists background color transparent:

// Removes background from List in SwiftUI
extension NSTableView {
    open override func viewDidMoveToWindow() {
        super.viewDidMoveToWindow()
        
        backgroundColor = NSColor.clear
        if let esv = enclosingScrollView {
            esv.drawsBackground = false
        }
    }
}

enter image description here

..........

..........

..........

the following code makes ALL OF TextEditors background color transparent:

extension NSTextView {
    open override var frame: CGRect {
        didSet {
            backgroundColor = .clear
            drawsBackground = true
        }
    }
}

Solution 11 - Swift

Someone may find this useful if attempting to create a floating type cell with SwiftUI using .listRowBackground and applying .padding

var body: some View {
    NavigationView {
        List {
            ForEach (site) { item in
                HStack {
                    Text(String(item.id))
                    
                    VStack(alignment: .leading) {
                        Text(item.name)
                        Text(item.crop[0])
                    }

                }.listRowBackground(Color.yellow)
                      .padding(.trailing, 5)
                      .padding(.leading, 5)
                      .padding(.top, 2)
                      .padding(.bottom, 2))
            }
        }
            .navigationBarTitle(Text("Locations"))
    }
}

Solution 12 - Swift

The answer by Islom Alimov https://stackoverflow.com/a/59970379/9439097 seems to be the best implementation so far in my opinion.

Only drawback: this also changes the background color of all other list views in your app, so you need to manually change them back unless you want the same color everywhere.

Here is an example view:

import SwiftUI

struct TestView1: View {
    
    init(){
        UITableView.appearance().backgroundColor = UIColor(Color.clear)
    }
    
    @State var data = ["abc", "def"]
    
    var body: some View {
        VStack {
            List {
                ForEach(data, id: \.self) {element in
                    Text("\(String(describing: element))")
                }
                .background(Color.green)
                .listRowBackground(Color.blue)
                
            }
            .background(Color.yellow)
            Spacer()
            Color.red
        }
    }
}

struct TestView1_Previews: PreviewProvider {
    static var previews: some View {
        TestView1()
    }
}

produces:

https://i.stack.imgur.com/bY7Bo.png" width="250" />

Solution 13 - Swift

For me, a perfect solution to change the background of List in SwiftUI is:

struct SomeView: View {
    init(){
    UITableView.appearance().backgroundColor = UIColor(named: "backgroundLight")
      }
...

}

Solution 14 - Swift

I assume the listRowPlatterColor modifier should do this, but isn't as of Xcode 11 Beta 11M336w

var body: some View {
    List(pokemon) { pokemon in
        PokemonCell(pokemon: pokemon)
            .listRowPlatterColor(.green)
    }
}

Solution 15 - Swift

List is not perfect yet.

An option would be to use it like this -> List { ForEach(elements) { }} instead of List($elements)

On my end this is what worked best up to now. Like @FontFamily said, it shouldn't break any List default behaviors like swiping.

Solution 16 - Swift

.colorMultiply(...)

As an option you can .colorMultiply(Color.yourColor) modifier.

Warning: this does not change the color! This only applies the Multiply modifier to the current color. Please read the question before any action, because you are probably looking for: "How to CHANGE the background color of a List in SwiftUI" and this will not work for you. ❄️

Example:

List (elements, id:\.self ) { element in

     Text(element)

}
.colorMultiply(Color.red) <--------- replace with your color

enter image description here

Solution 17 - Swift

Simply Add UITableView appearance background color in init() method and add list style (.listStyle(SidebarListStyle()). Don't forget to import UIKit module

struct HomeScreen: View {
init() {
    UITableView.appearance().backgroundColor = .clear
}

let tempData:[TempData] = [TempData( name: "abc"),
                         TempData( name: "abc"),
                         TempData( name: "abc"),
                         TempData( name: "abc")]

var body: some View {
    ZStack {
        Image("loginBackgound")
            .resizable()
            .scaledToFill()
        List{
            ForEach(tempData){ data in
                Text(data.name)
            }
        }
        .listStyle(SidebarListStyle())
        
    }
    .ignoresSafeArea(edges: .all)
}
}

Solution 18 - Swift

Make extension List like:

extension List{
@available(iOS 14, *)
func backgroundList(_ color: Color = .clear) -> some View{
    UITableView.appearance().backgroundColor = UIColor(color)
    return self
}

}

Solution 19 - Swift

I've inspired some of the configurator used to config per page NavigationView nav bar style and write some simple UITableView per page configurator not use UITableView.appearance() global approach

   import SwiftUI
    
    struct TableViewConfigurator: UIViewControllerRepresentable {
        
        var configure: (UITableView) -> Void = { _ in }
        
        func makeUIViewController(context: UIViewControllerRepresentableContext<TableViewConfigurator>) -> UIViewController {
            
            UIViewController()
        }
        
        func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<TableViewConfigurator>) {
            
            let tableViews = uiViewController.navigationController?.topViewController?.view.subviews(ofType: UITableView.self) ?? [UITableView]()
            
            for tableView in tableViews {
                self.configure(tableView)
            }
        }
    }

Then there is UIView extension needed to find all UITableViews

extension UIView {
    func subviews<T:UIView>(ofType WhatType:T.Type) -> [T] {
        var result = self.subviews.compactMap {$0 as? T}
        for sub in self.subviews {
            result.append(contentsOf: sub.subviews(ofType:WhatType))
        }
        return result
    }
}

And usage at the end is:

List {
                      
}.background(TableViewConfigurator {
    $0.backgroundColor = .red
})

Maybe one thing should be improved that is usage of navigationController?.topViewController to make it work even without navigationController in view controllers hierarchy

Solution 20 - Swift

If anyone came here looking for solutions for background in landscape not full width on iPhone X/11 try:

.listRowBackground(Color("backgroundColour").edgesIgnoringSafeArea(.all))

Solution 21 - Swift

If you want to avoid setting the appearance for all table views globally, you can combine UITableView.appearance(whenContainedInInstancesOf:) with UIHostingController. Thanks DanSkeel for the comment you left above pointing this out. This is how I used it:

public class ClearTableViewHostingController<Content>: UIHostingController<Content> where Content: View {
    public override func viewDidLoad() {
        UITableView.appearance(whenContainedInInstancesOf: [ClearTableViewHostingController<Content>.self]).backgroundColor = .clear
    }
}

You can use ClearTableViewHostingController like this:

let view = MyListView()
let viewController = ClearTableViewHostingController(coder: coder, rootView: view)

Then in your view you can set the list background color like so:

List {
    Text("Hello World")
}
.background(Color.gray)

Solution 22 - Swift

Using UITableView.appearance().backgroundColor is not a good idea as it changes the backgroundColor of all tables. I found a working solution for color changing at the exact table you selected in iOS 14, 15.

We will change the color using a modifier that needs to be applied inside the List

extension View {
    
    func backgroundTableModifier(_ color: UIColor? = nil) -> some View {
        self.modifier(BackgroundTableModifier(color: color))
    }

}

Our task is to find the UITableView and after that change the color.

private struct BackgroundTableModifier: ViewModifier {
    
    private let color: UIColor?
    @State private var tableView: UITableView?
    
    init(color: UIColor?) {
        self.color = color
    }
    
    public func body(content: Content) -> some View {
        if tableView?.backgroundColor != color {
            content
                .overlay(BackgroundTableViewRepresentable(tableBlock: { tableView in
                    tableView.backgroundColor = color
                    self.tableView = tableView
                }))
        } else {
            content
        }
    }
}

private struct BackgroundTableViewRepresentable: UIViewRepresentable {
    
    var tableBlock: (UITableView) -> ()
    
    func makeUIView(context: Context) -> BackgroundTableView  {
        let view = BackgroundTableView(tableBlock: tableBlock)
        return view
    }
    
    func updateUIView(_ uiView: BackgroundTableView, context: Context) {}
}

class BackgroundTableView: UIView {
    
    var tableBlock: (UITableView) -> ()
    
    init(tableBlock: @escaping (UITableView) -> ()) {
        self.tableBlock = tableBlock
        super.init(frame: .zero)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        if let tableView = findTableView(in: self) {
            tableBlock(tableView)
        }
    }
    
    private func findTableView(in view: UIView) -> UITableView? {
        if let tableView = view as? UITableView {
            return tableView
        }
        
        if let superView = view.superview {
            return findTableView(in: superView)
        }
        
        return nil
    }
    
}

In order to find UITableView, the modifier must be inside the List. Naturally, you need to ensure that the modifier is called only once, you do not need to apply it to each row. Here is an example of usage

List {
   rows()
     .backgroundTableModifier(.clear)
}

func rows() -> some View {
    ForEach(0..<10, id: \.self) { index in
        Row()
    }
}

Solution 23 - Swift

you can use introspect library from Github to set the background color for the underlying table view like this:

List { ... } .introspectTableView { tableView in
                tableView.backgroundColor = .yellow
            }

Solution 24 - Swift

For some reason color change is not working, you can try the .listStyle to .plain

Code:

struct ContentView: View {
var body: some View {
    VStack {
        Text("Test")

        List {
            ForEach(1 ..< 4) { items in
                Text(String(items))
            }
        }
        .listStyle(.plain)
    }
}

Solution 25 - Swift

Xcode Version 12.4

The Background property worked for me, but with the mandatory use of Opacity. Without opacity it is not work.

List {
            ForEach(data, id: \.id) { (item) in
                ListRow(item)
                    .environmentObject(self.data)
            }
        }
        .background(Color.black)
        .opacity(0.5)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionandromedainiativeView Question on Stackoverflow
Solution 1 - SwiftMarius WaldalView Answer on Stackoverflow
Solution 2 - SwiftMahmoud EldesoukyView Answer on Stackoverflow
Solution 3 - SwiftSteve HamView Answer on Stackoverflow
Solution 4 - SwiftVishal PatelView Answer on Stackoverflow
Solution 5 - SwiftCameron McBroomView Answer on Stackoverflow
Solution 6 - SwiftAriView Answer on Stackoverflow
Solution 7 - SwiftJake StricklerView Answer on Stackoverflow
Solution 8 - SwiftMustafa OzhanView Answer on Stackoverflow
Solution 9 - SwiftAmitView Answer on Stackoverflow
Solution 10 - SwiftAndrewView Answer on Stackoverflow
Solution 11 - Swiftcaleb81389View Answer on Stackoverflow
Solution 12 - SwiftcharelfView Answer on Stackoverflow
Solution 13 - SwiftIslom AlimovView Answer on Stackoverflow
Solution 14 - SwiftEmma K AlexandraView Answer on Stackoverflow
Solution 15 - SwiftOleg G.View Answer on Stackoverflow
Solution 16 - SwiftPedro TrujilloView Answer on Stackoverflow
Solution 17 - SwiftRajesh Kumar SahilView Answer on Stackoverflow
Solution 18 - SwiftBadreView Answer on Stackoverflow
Solution 19 - SwiftMichał ZiobroView Answer on Stackoverflow
Solution 20 - SwiftsacriorvView Answer on Stackoverflow
Solution 21 - SwiftMattLView Answer on Stackoverflow
Solution 22 - SwiftAndrey DyatkovView Answer on Stackoverflow
Solution 23 - SwiftJAHeliaView Answer on Stackoverflow
Solution 24 - SwiftAs If PrinceView Answer on Stackoverflow
Solution 25 - SwiftDinarView Answer on Stackoverflow