How to specify different list style in .listStyle() based on current device?

public var body: some View {
    List {
        ...
    }
    .listStyle(isPhone ? .plain : .sidebar)
}

When I write code like above, I get a compile error: "Member 'sidebar' in 'PlainListStyle' produces result of type 'SidebarListStyle', but context expects 'PlainListStyle'"

It looks like the root cause is: Protocol 'ListStyle' can only be used as a generic constraint because it has Self or associated type requirements

How can I solve this problem?

Thanks,

Accepted Reply

I had this problem before and my answer to your question based off of that would be to create a custom ViewModifier and use @ViewBuilder so you can handle the compilation error message.

Something like this should work:

struct DeviceAdaptedListStyle: ViewModifier {
  var isPhone: Bool { ... }

  @ViewBuilder func body(content: Content) -> some View {
    if isPhone {
      content.listStyle(.plain)
    } else {
      content.listStyle(.sidebar)
    }
  }
}

extension List {
  func deviceAdaptedListStyle() -> some View {
    modifier(DeviceAdaptedListStyle())
  }
}

At the moment, there might be a better solution with Swift 5.5, but I haven't checked.

Replies

I had this problem before and my answer to your question based off of that would be to create a custom ViewModifier and use @ViewBuilder so you can handle the compilation error message.

Something like this should work:

struct DeviceAdaptedListStyle: ViewModifier {
  var isPhone: Bool { ... }

  @ViewBuilder func body(content: Content) -> some View {
    if isPhone {
      content.listStyle(.plain)
    } else {
      content.listStyle(.sidebar)
    }
  }
}

extension List {
  func deviceAdaptedListStyle() -> some View {
    modifier(DeviceAdaptedListStyle())
  }
}

At the moment, there might be a better solution with Swift 5.5, but I haven't checked.

It works like a charm! Thank you!