I'm attempting to create reusable SwiftUI View
for a framework, which can then be used across both iOS/iPadOS and macOS.
This generally works fine; however, because macOS views don't have navigation bars, including a navigation bar title (important for iOS) causes an error when the view's included in a macOS target:
.navigationBarTitle(Text("Page Title"))
Value of type '...' has no member 'navigationBarTitle'
Any suggestions on a conditional compilation (or any other) approach that can allow the same view to build for both platforms?
The closest I've come is the following. Including the extra Text
view is easy enough, but because the bar title's a modifier, wrapping just that part in conditional compilation produces other errors:
public struct ExampleView: View {
private let pageTitle = "Page Title"
public var body: some View {
VStack(alignment: .center) {
#if os(macOS)
Text(pageTitle)
.font(.title)
#endif
Spacer()
Text("This is the view content")
Spacer()
}
#if !os(macOS)
.navigationBarTitle(Text(pageTitle))
#endif
}
}
Unexpected platform condition (expected 'os', 'arch', or 'swift')
Function declares an opaque return type, but has no return statements in its body from which to infer an underlying type
I established one approach: Move the main content to another View
property, then modify it to add the navbar title (if needed) before returning it as body
. When it's separated this way, conditional compilation can be used.
It's a bit inelegant, but it works. It can also be used to set macOS-specific things, such as the view's overall frame size. Suggestions on a better approach are welcome!
Swift v5.1
public struct ExampleView: View {
private let pageTitle = "Page Title"
#if !os(macOS)
public var body: some View {
main.navigationBarTitle(Text(pageTitle))
}
#else
public var body: some View {
main.frame(
minWidth: 500,
minHeight: 500
)
}
#endif
public var main: some View {
VStack(alignment: .center) {
#if os(macOS)
Text(pageTitle)
.font(.title)
#endif
Spacer()
Text("This is the view content")
Spacer()
}
}
}
you can add an extension to View struct. It will put conditional compilation outside the block and work as you expect
#if os(macOS)
extension View {
func navigationBarTitle(_ title: Text) -> some View {
return self
}
}
#endif
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With