Good day! In SwiftUI, is it possible to use a modifier only for a certain os target? In the following code I would like to use the modifier .listStyle(SidebarListStyle()) on
You can create a View
extension and use it like this:
List {
// ...
}
.ifOS(.macOS) {
$0.listStyle(SidebarListStyle())
}
Here's the implementation:
enum OperatingSystem {
case macOS
case iOS
case tvOS
case watchOS
#if os(macOS)
static let current = macOS
#elseif os(iOS)
static let current = iOS
#elseif os(tvOS)
static let current = tvOS
#elseif os(watchOS)
static let current = watchOS
#else
#error("Unsupported platform")
#endif
}
extension View {
/**
Conditionally apply modifiers depending on the target operating system.
```
struct ContentView: View {
var body: some View {
Text("Unicorn")
.font(.system(size: 10))
.ifOS(.macOS, .tvOS) {
$0.font(.system(size: 20))
}
}
}
```
*/
@ViewBuilder
func ifOS(
_ operatingSystems: OperatingSystem...,
modifier: @escaping (Self) -> Content
) -> some View {
if operatingSystems.contains(OperatingSystem.current) {
modifier(self)
} else {
self
}
}
}
However, this will not work if you try to use a method that is not available for all the platforms you target. The only way to make that work is to use #if os(…)
directly.
I have an extension that makes it easier to do that:
extension View {
/// Returns a type-erased version of `self`.
func eraseToAnyView() -> AnyView {
AnyView(self)
}
}
extension View {
// The closure unfortunately has to return `AnyView` as `some` cannot yet be used in return values in closures.
/**
Modify the view in a closure. This can be useful when you need to conditionally apply a modifier that is unavailable on certain platforms.
For example, imagine this code needing to run on macOS too where `View#actionSheet()` is not available:
```
struct ContentView: View {
var body: some View {
Text("Unicorn")
.modify {
#if os(iOS)
return $0.actionSheet(…).eraseToAnyView()
#endif
return nil
}
}
}
```
*/
@ViewBuilder
func modify(_ modifier: (Self) -> AnyView?) -> some View {
if let view = modifier(self) {
view
} else {
self
}
}
}