Search code examples
swiftuiviewmodifierios16

iOS 16 View Modifier not consistent across List headers


Since iOS changed List to use UICollectionView instead of UITableView, all my Section headers have taken on the background colors of my list cells.

I use a ThemedList to color my lists throughout the app:

struct ThemedList<Content>: View where Content: View {
    
    @ViewBuilder var content: () -> Content
    
    var body: some View {
        List {
            content()
                .listRowBackground(Color.red)
        }
    }
}

Simply replacing List with ThemedList throughout my app worked fine in iOS 15:

struct SidebarView: View {
    var body: some View {
        ThemedList {
            Section("Header") {
                Text("Row")
                Text("Row")
                Text("Row")
            }
        }
    }
}

enter image description here

Now on iOS 16 it looks like this:

enter image description here

Ok, this should be a simple fix. Ive created a ThemedSection that makes the background .clear:

struct ThemedSection<Header, Content, Footer> {
    @ViewBuilder var header: () -> Header
    @ViewBuilder var footer: () -> Footer
    @ViewBuilder var content: () -> Content
}
extension ThemedSection : View where Header : View, Content : View, Footer : View {
    
    var body: some View {
        Section {
            content()
        } header: {
            header()
                .listRowBackground(Color.clear)
        } footer: {
            footer()
                .listRowBackground(Color.clear)
        }
    }
}

and initialisers that mimic those of Section

extension ThemedSection where Header == Text, Content : View, Footer == EmptyView {
    
    init<S>(_ title: S, @ViewBuilder content: @escaping () -> Content) where S : StringProtocol {
        
        self.content = content
        self.header = { Text(title) }
        self.footer = { EmptyView() }
    }
}

Replacing all Section with ThemedSection in my app:

struct SidebarView: View {
    var body: some View {
        ThemedList {
            ThemedSection("Header") {
                Text("Row")
                Text("Row")
                Text("Row")
            }
        }
    }
}

enter image description here

Now the big problem. Not all of my ThemedSection's show the clear header.

If I add my view to a NavigationView on it's own, it's still fine. If I add a second view to be the current detail view on iPad, then my list section no longer works:

struct ContentView: View {
    var body: some View {
        NavigationView {
            SidebarView()
            Text("iPad selected initial view") // Remove line for headers to appear clear
        }
    }
}

struct SidebarView: View {
    var body: some View {
        ThemedList {
            ThemedSection("Header") {
                Text("Row")
                Text("Row")
                Text("Row")
            }
        }
    }
}

enter image description here

I can even have the same view as my master and detail in the navigation and the detail works but the master doesn't.

struct ContentView: View {
    var body: some View {
        NavigationView {
            SidebarView()
            SidebarView()
        }
    }
}

enter image description here

Can someone explain what's going on here and how I can fix it?

Full code gist


Solution

  • Set the .listStyle so you have consistency

    Because Apple can decide what .listStyle is best, it has changed with every version of SwiftUI for different settings.

    If you set it, then it takes your preference not Apple's preference for the circumstance.

    The photos you show are .plain for the sidebar and .grouped for the detail.