可重用跨平台(iOS和macOS)视图中的SwiftUI导航栏标题

时间:2019-12-16 15:38:30

标签: swift macos frameworks swiftui navigationbar

我正在尝试为框架创建可重用的SwiftUI View,然后可以在iOS / iPadOS和macOS上使用它。

这通常可以正常工作;但是,由于macOS视图没有导航栏,因此当视图包含在macOS目标中时,包括导航栏标题(对于iOS而言很重要)会导致错误:

.navigationBarTitle(Text("Page Title"))

  

类型'...'的值没有成员'navigationBarTitle'

关于条件编译(或任何其他)方法的任何建议都可以为两个平台构建相同的视图?

我来的最接近的是以下。包括额外的Text视图很容易,但是由于栏标题是修饰符,因此在条件编译中仅包装该部分会产生其他错误:

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
    }
}
  

意外的平台状况(预期的“ os”,“ arch”或“ swift”)

     

函数声明了一个不透明的返回类型,但是在其主体中没有用于从其推断基础类型的返回语句

2 个答案:

答案 0 :(得分:1)

您可以向View结构添加扩展名。它将条件编译放在块外,并按您期望的那样工作

#if os(macOS)
extension View {
    func navigationBarTitle(_ title: Text) -> some View {
        return self
    }
}
#endif

答案 1 :(得分:0)

我建立了一种方法:将主要内容移动到另一个View属性,然后对其进行修改以添加导航栏标题(如果需要),然后将其返回为body。当以这种方式分开时,可以使用条件编译。

这有点不雅致,但可以。它也可以用于设置特定于macOS的内容,例如视图的整体框架大小。欢迎提出更好的方法的建议!

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()
        }
    }
}