1

My iPad app makes use of a 3-column layout using SwiftUI's NavigationView, 2 Lists, and then the content view. The first List acts as the primary navigation screen, and the (relevant) code looks roughly like this:

var body: some View {
    List {
          ...snip...
        }
    }
    .listStyle(SidebarListStyle())
    .accentColor(.white)
    .introspectTableView { tableView in
        tableView.backgroundColor = UIColor(Color.blue)
    }
    .navigationBarItems(trailing: Button(action: { self.isCreating = true }) {
        Label("", systemImage: "plus")
            .foregroundColor(.white)
    })
}

As shown in the code, I was using the awesome Introspect library to get access to the underlying UITableView so I could set the background color. In iOS 14 this renders properly, as a List with a blue background. (See screenshot below)

enter image description here

However, in iOS 15 the background color is not applied. (See screenshot)

enter image description here

I have tried a couple different methods for setting the background color in iOS 15. The Introspect code doesn't seem to get called at all, so I tried:

List {
}
.background(Color.blue)

That did absolutely nothing. I also tried setting UITableView.appearance().backgroundColor to the appropriate value, however that will change the background of all UITableViews globally. That is not the behavior I want. I only want this one List to have that background color.

Is this a bug in iOS 15 or SwiftUI? Is there a new way for setting the background color on a List? Does this have something to do with the fact that my listStyle is set to SidebarListStyle?

Any help or guidance would be greatly appreciated!!

1
  • Introspect is a hack for SwiftUI, every place where you use it is under risk of stop working with any next iOS update, even minor. I would not recommend to use it for production - only for investigations. Commented Oct 25, 2021 at 4:50

2 Answers 2

6

I managed to change the background of list with:

List {

   Section("Section") {
      /// ...
   }
   .listRowBackground(Color.clear)
}
.listStyle(.plain)
.background(.blue)
Sign up to request clarification or add additional context in comments.

2 Comments

Annoying that this only works with list style plain and not with the default style with rounded corners, ie grouped.
The best solution over my research ))
1

you could try a combination of things, such as in this example:

EDIT1: to make it work with the sidebar, tested on iPad ios15.

struct ContentView: View {
    let data = (1...10).map{ String($0) }
    
    init() {
        UITableView.appearance().backgroundColor = .clear // <-- here
    }
    
    var body: some View {
        NavigationView {
            ZStack {
                Color.blue.ignoresSafeArea() // <-- here blue background
                List {
                    ForEach(data, id: \.self) { tx in
                        // Text(tx).foregroundColor(.white) // <-- white text
                      NavigationLink(tx, destination: Text("destination " + tx)).foregroundColor(.white)
                    }
                    .listRowBackground(Color.blue) // <-- list row matching background
                }
                .listStyle(.sidebar) // <-- here
            }
        }
    } 
}

EDIT2: avoiding global color change.

Ok, whenever you action another view, put the color back, such as in this example using onTapGesture. You can also use onDisappear or onAppear or any other scheme to change the color for all future views, depending on your needs.

struct ContentView: View {
    let data = (1...10).map{ String($0) }
    @State var activate: Bool = false
    @State var selection: String?
    
    init() {
        UITableView.appearance().backgroundColor = .clear // <-- here
    }
    
    var body: some View {
        NavigationView {
            ZStack {
                Color.blue.ignoresSafeArea() // <-- here blue background
                List {
                    ForEach(data, id: \.self) { tx in
                        NavigationLink(tx, destination: SecView(text: tx), tag: tx, selection: $selection)
                            .foregroundColor(.white)
                            .onTapGesture() {
                                // --- here --- whatever color you want
                                UITableView.appearance().backgroundColor = .systemGroupedBackground
                                selection = tx
                            }
                    }.listRowBackground(Color.blue) // <-- list row matching background
                } .listStyle(.sidebar) // <-- here
            }
        }
    }
}

struct SecView: View {
    @State var text: String
    let data = (1...10).map{ String($0) }

    var body: some View {
        List {
            ForEach(data, id: \.self) { tx in
                NavigationLink(text + " " + tx, destination: SecView(text: tx))
            }
        }
    }
}

4 Comments

Would I still get a layout similar to SidebarListStyle? (Grouping, collapsable sections, etc.) Is there a way to mimic that manually?
updated my answer to cater for the sidebar.
So, again, I know I could use UITableView.appearance(), however that changes EVERY List. I only want to change this one. I don't want to make a global change.
updated my answer with a possible solution to avoid global background color setting. Works well for me.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.