Passing variable to listStyle view modifier

It's unclear to me what change I need to make to get this code to compile. It's a very small app for experimenting with different list styles. See the comments in the code.

struct ContentView: View {
    @State private var selectedName = "plain"
    @State private var selectedStyle: any ListStyle = .plain

    let styles: [String: any ListStyle] = [
        // .bordered, // not in iOS
        // .carousel, // not in iOS
        // .elliptical, // not in iOS
        "grouped": .grouped,
        "inset": .inset,
        "InsetGrouped": .insetGrouped,
        "plain": .plain,
        "sidebar": .sidebar
    ]

    var styleNames: [String] {
        Array(styles.keys)
    }

    var body: some View {
        VStack { // error: "Type 'any View' cannot conform to 'View'"
            Picker("List Style", selection: $selectedName) {
                ForEach(styleNames, id: \.self) { name in
                    Text(name).tag(name)
                }
            }
            .onChange(of: selectedName) { _ in
                selectedStyle = styles[selectedName]!
            }

            List {
                Section("Breakfast") {
                    Text("pancakes")
                    Text("bacon")
                    Text("orange juice")
                }
                Section("Lunch") {
                    Text("sandwich")
                    Text("chips")
                    Text("lemonade")
                }
                Section("Dinner") {
                    Text("spaghetti")
                    Text("bread")
                    Text("water")
                }
            }
            // The real issue is here because the type of selectedStyle
            // is "any ListStyle" instead of "ListStyle",
            // but I don't know how to fix this.
            .listStyle(selectedStyle)
        }
    }
}

You need to wrap your List into AnyView so it will be the same code as you wrote except from this:

AnyView(
  List {

  }
   .listStyle(selectedStyle)
)

The reason for that as far as I understand is that under the hood your some View is actually very complex generic type like ViewPair<Picker<...>, List<...>> and every part of that type should be determinated, but because you are storing any ListStyle which can be anything that conforms to ListStyle and which will form as result any View you need to make this to concrete type that conforms to View which in our case is AnyView type

Putting all the boilerplate stuff that goes between SwiftUI.ListStyle and be able to iterate a list of all ListStyle, it's better to put these thing inside a enum:

import SwiftUI

extension View {
    var anyView: AnyView {
        AnyView(self)
    }
}


// Our ListStyle each case corresponds to a SwiftUI.ListStyle
// Here we make it CaseIterable for SwiftUI.ForEach
// and the UI Display name
enum ListStyle: String, CaseIterable, Hashable {
    case grouped = "Grouped"
    case inset = "Inset"
    case insetGrouped = "InsetGrouped"
    case plain = "Plain"
    case sidebar = "Sidebar"
    
    // map to SwiftUI ListStyle
    var style: any SwiftUI.ListStyle {
        switch self {
        case .grouped:
            return .grouped
        case .inset:
            return .inset
        case .insetGrouped:
            return .insetGrouped
        case .plain:
            return .plain
        case .sidebar:
            return .sidebar
        }
    }
    
    var displayName: String {
        String(localized: String.LocalizationValue(self.rawValue))
    }
}


struct AnyViewDemo: View {
    @State private var selectedStyle = ListStyle.plain

    var body: some View {
        VStack {
            Picker("List Style", selection: $selectedStyle) {
                ForEach(ListStyle.allCases, id: \.self) {
                    Text($0.displayName).tag($0)
                }
            }

            List {
                Section("Breakfast") {
                    Text("pancakes")
                    Text("bacon")
                    Text("orange juice")
                }
                Section("Lunch") {
                    Text("sandwich")
                    Text("chips")
                    Text("lemonade")
                }
                Section("Dinner") {
                    Text("spaghetti")
                    Text("bread")
                    Text("water")
                }
            }
            .listStyle(selectedStyle.style)
            .anyView
        }
    }
}

struct AnyViewDemo_Previews: PreviewProvider {
    static var previews: some View {
        AnyViewDemo()
    }
}

Ah! I see now that you suggested parens after AnyView, not braces for a closure. Sorry, I misread your suggestion. It does work!

Here is the code I landed on:

import SwiftUI

// This type enables iterating over objects that conform to the
// ListStyle protocol and getting their names as a String.
// The main reason this is needed is that the type [any ListStyle]
// does not conform to Equatable and Hashable which are required by ForEach.
struct MyListStyle: Equatable, Hashable {
    let style: any ListStyle

    var name: String {
        // All names contain "ListStyle" and we want the part before that.
        var name = String(describing: style)
        let index = name.range(of: "ListStyle")?.lowerBound
        if let index { name.removeSubrange(index...) }
        return name
    }

    init(_ style: any ListStyle) {
        self.style = style
    }

    static func == (lhs: MyListStyle, rhs: MyListStyle) -> Bool {
        lhs.name == rhs.name
    }

    func hash(into hasher: inout Hasher) {
        hasher.combine(name)
    }
}

struct ContentView: View {
    @State private var selectedStyle = MyListStyle(.plain)

    let styles: [MyListStyle] = [
        // "bordered": .bordered, // not in iOS
        // "carousel": .carousel, // not in iOS
        // "elliptical": .elliptical, // not in iOS
        MyListStyle(.grouped),
        MyListStyle(.inset),
        MyListStyle(.insetGrouped),
        MyListStyle(.plain),
        MyListStyle(.sidebar)
    ]

    var body: some View {
        VStack {
            Picker("List Style", selection: $selectedStyle) {
                ForEach(styles, id: \.self) { style in
                    Text(style.name).tag(style)
                }
            }

            // This avoids the error
            // "Type 'any View' cannot conform to 'View'".
            AnyView(
                List {
                    Section("Breakfast") {
                        Text("pancakes")
                        Text("bacon")
                        Text("orange juice")
                    }
                    Section("Lunch") {
                        Text("sandwich")
                        Text("chips")
                        Text("lemonade")
                    }
                    Section("Dinner") {
                        Text("spaghetti")
                        Text("bread")
                        Text("water")
                    }
                }
                .listStyle(selectedStyle.style)
            )
        }
    }
}

@mvolkmann glad that everything works!