Search code examples
macosuser-interfaceswiftuiinterface

How do I get items added to MyList to have Alternating background colors


I originally had alternating row backgrounds on the list when that didn't work I tried putting it on the rows which also did not work. I've tried other methods such as using % mod operator to select a specific color which also did not work. Alternating row backgrounds initially works with an empty list. The added items remove the alternate colors.

struct MyList<Content>: View where Content: View {
    @ViewBuilder let content: () -> Content
    var body: some View {
        List { content( )
            .alternatingRowBackgrounds( )
        }
        .listStyle( .bordered )
//      .cornerRadius(10)
        .padding(.vertical, 2)
        .alternatingRowBackgrounds( )
        .listRowInsets(EdgeInsets())
        .listRowSeparator(.hidden)
    }
}

Edit - 1

I rewrote the above to accept a simple array of strings so you can see the issue:

func MyList(_ data: [String]) -> some View {
    let sortedData = data.sorted {
        $0.localizedCaseInsensitiveCompare($1) == .orderedAscending
    }

    return List {
        LazyVGrid(columns: [GridItem(.flexible())], spacing: 2) {
            ForEach(sortedData, id: \.self) { curItem in
                    HStack(spacing: 10) {
                    Text( curItem )
                    Spacer()
                }
            }
        }
    }
    .frame(maxWidth: .infinity, alignment: .leading) // Left-align the text
    .listStyle(.bordered)
    .padding(.vertical, 2)
    .alternatingRowBackgrounds()
    .listRowInsets(EdgeInsets())
    .listRowSeparator(.hidden)
}

enter image description here


Solution

  • alternatingRowBackgrounds is only available on macOS.

    macOS example code

    struct ContentView: View {
        @State private var arr = ["item-1","item-2","item-3","item-4"]
        
        var body: some View {
            VStack {
                Button("Add item") {
                    arr.append("item-\(arr.count+1)")
                }
                List(arr, id: \.self) { item in
                    Text(item)
                }
                .listStyle(.bordered)
                .alternatingRowBackgrounds()
                .padding(.vertical, 2)
                .listRowInsets(EdgeInsets())
                .listRowSeparator(.hidden)
            }
        }
    }
     
    

    For iOS17 you could try a different approach using enumerated and a listRowBackground with condition.

    iOS17 example code:

        struct ContentView: View {
        @State private var arr = ["item-1","item-2","item-3","item-4"]
        
        var body: some View {
            VStack {
                Button("Add item") {
                    arr.append("item-\(arr.count+1)")  
                }
                List(Array(arr.enumerated()), id: \.offset) { index, item in
                    Text(item)
                        .listRowBackground(index % 2 == 0 ? Color.blue : Color.yellow)
                }
                .listStyle(.plain)
                .padding(.vertical, 2)
                .listRowInsets(EdgeInsets())
                .listRowSeparator(.hidden)
            }
        }
    }
    

    You could try this using your MyList construct:

    struct ContentView: View {
        @State private var arr = ["item-1","item-2","item-3","item-4"]
        
        var body: some View {
            MyList(arr)
        }
        
        @ViewBuilder
        func MyList(_ data: [String]) -> some View {
            let sortedData = data.sorted {
                $0.localizedCaseInsensitiveCompare($1) == .orderedAscending
            }
            List(sortedData, id: \.self) { curItem in
                LazyVGrid(columns: [GridItem(.flexible())], spacing: 2) {
                    HStack(spacing: 10) {
                        Text( curItem )
                        Spacer()
                    }
                }
            }
            .frame(maxWidth: .infinity, alignment: .leading) // Left-align the text
            .listStyle(.bordered)
            .padding(.vertical, 2)
            .alternatingRowBackgrounds()
            .listRowInsets(EdgeInsets())
            .listRowSeparator(.hidden)
        }
        
    }