Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
macOS SwiftUI导航,用于单一视图_Macos_Navigation_Swiftui_Macos Catalina_Swiftui Navigationview - Fatal编程技术网

macOS SwiftUI导航,用于单一视图

macOS SwiftUI导航,用于单一视图,macos,navigation,swiftui,macos-catalina,swiftui-navigationview,Macos,Navigation,Swiftui,Macos Catalina,Swiftui Navigationview,我正在尝试为我的macOS SwiftUI状态栏应用程序创建设置视图。到目前为止,我的实现一直使用NavigationView和NavigationLink,但是当设置视图将父视图推到一边时,此解决方案会生成半视图。下面的屏幕截图和代码示例 导航侧栏 struct ContentView:View{ var body:一些观点{ VStack{ 导航视图{ NavigationLink(目标:SecondView()){ 文本(“转到下一个视图”) }} }.frame(宽:800,高:600

我正在尝试为我的macOS SwiftUI状态栏应用程序创建设置视图。到目前为止,我的实现一直使用
NavigationView
NavigationLink
,但是当设置视图将父视图推到一边时,此解决方案会生成半视图。下面的屏幕截图和代码示例

导航侧栏

struct ContentView:View{
var body:一些观点{
VStack{
导航视图{
NavigationLink(目标:SecondView()){
文本(“转到下一个视图”)
}}
}.frame(宽:800,高:600,对齐:。中心)}
}
结构第二视图:视图{
var body:一些观点{
VStack{
文本(“这是第二个视图”)
}.框架(宽:800,高:600,对齐:。中心)
}
}
我能找到的少量信息表明,在macOS上使用SwiftUI是不可避免的,因为在macOS上无法使用iOS上的“全屏”
NavigationView
StackNavigationViewStyle

是否有一种简单甚至复杂的方法来实现到设置视图的转换,该视图占据了SwiftUI for macOS的整个框架?如果没有,是否可以使用
AppKit
调用用SwiftUI编写的视图对象


也是一个敏捷的新手-请温柔。

您可以使用

 .navigationViewStyle(StackNavigationViewStyle())

下面是一个简单的示例,演示了定制类似导航的解决方案的可能方法。使用Xcode 11.4/macOS 10.15.4进行测试

注意:背景色用于更好的可见性

我已经扩展了他的伟大建议,并为macOS(甚至iOS,如果你愿意的话)创建了一个通用的、可重用的
StackNavigationView
。一些亮点:

  • 它支持任意数量的子视图(在任何布局中)
  • 它会自动为每个子视图添加一个“后退”按钮(目前仅为文本,但如果使用macOS 11+,则可以在图标中切换)

Swift v5.2:

struct StackNavigationView<RootContent, SubviewContent>: View where RootContent: View, SubviewContent: View {
    
    @Binding var currentSubviewIndex: Int
    @Binding var showingSubview: Bool
    let subviewByIndex: (Int) -> SubviewContent
    let rootView: () -> RootContent
    
    var body: some View {
        VStack {
            VStack{
                if !showingSubview { // Root view
                    rootView()
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                        .transition(AnyTransition.move(edge: .leading)).animation(.default)
                }
                if showingSubview { // Correct subview for current index
                    StackNavigationSubview(isVisible: self.$showingSubview) {
                        self.subviewByIndex(self.currentSubviewIndex)
                    }
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .transition(AnyTransition.move(edge: .trailing)).animation(.default)
                }
            }
        }
    }
    
    init(currentSubviewIndex: Binding<Int>, showingSubview: Binding<Bool>, @ViewBuilder subviewByIndex: @escaping (Int) -> SubviewContent, @ViewBuilder rootView: @escaping () -> RootContent) {
        self._currentSubviewIndex = currentSubviewIndex
        self._showingSubview = showingSubview
        self.subviewByIndex = subviewByIndex
        self.rootView = rootView
    }
    
    private struct StackNavigationSubview<Content>: View where Content: View {
        
        @Binding var isVisible: Bool
        let contentView: () -> Content
        
        var body: some View {
            VStack {
                HStack { // Back button
                    Button(action: {
                        self.isVisible = false
                    }) {
                        Text("< Back")
                    }.buttonStyle(BorderlessButtonStyle())
                    Spacer()
                }
                .padding(.horizontal).padding(.vertical, 4)
                contentView() // Main view content
            }
        }
    }
}

注意:类似的泛型要求所有子视图的类型相同。如果不是这样,您可以将它们包装在
AnyView
中,就像我在这里所做的那样。如果您对所有子视图使用一致的类型(根视图的类型不需要匹配),则不需要使用
AnyView
包装器。

Heyo,所以我遇到的一个问题是,我希望有多个navigationView层,我不确定这是否也是您的尝试,但如果是:MacOS不会继承NavigationView。 也就是说,您需要使用自己的
NavigationView
提供您的详细视图(或者您的案例中的
SecondView
)。因此,只需嵌入像
[…],destination:NavigationView{SecondView()})[…]
就可以了

但是,小心!对iOS目标执行相同操作将导致意外行为。因此,如果您将两者都作为目标,请确保使用
#if os(macOS)


但是,在创建设置视图时,我建议您也查看一下苹果提供的设置。

这似乎在Xcode 13中没有得到解决


在Xcode 13 Big Sur上测试,但不是在蒙特雷…

Ahh如果这么简单的话,我会得到一个构建错误“StackNavigationViewStyle”在macOS中不可用。刚才在苹果文档中看到,它仅在使用Mac Catalyst创建的应用程序中可用。这是否也可以将数据LazyGrid()->详细信息传递给ex?我试过了,但没有成功,因为您需要同时加载两个视图,这是一个简单而有效的解决方案。万分感谢!这是一个很好的解决方案。你知道如何停止同时应用于所有子视图的
.animation()
修改器吗?Asperi,你是最好的。这就是我一直在寻找的。是否可以用这种方法传递数据列表->详细信息?是否可以用这种方法传递数据列表->详细信息?
struct StackNavigationView<RootContent, SubviewContent>: View where RootContent: View, SubviewContent: View {
    
    @Binding var currentSubviewIndex: Int
    @Binding var showingSubview: Bool
    let subviewByIndex: (Int) -> SubviewContent
    let rootView: () -> RootContent
    
    var body: some View {
        VStack {
            VStack{
                if !showingSubview { // Root view
                    rootView()
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                        .transition(AnyTransition.move(edge: .leading)).animation(.default)
                }
                if showingSubview { // Correct subview for current index
                    StackNavigationSubview(isVisible: self.$showingSubview) {
                        self.subviewByIndex(self.currentSubviewIndex)
                    }
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .transition(AnyTransition.move(edge: .trailing)).animation(.default)
                }
            }
        }
    }
    
    init(currentSubviewIndex: Binding<Int>, showingSubview: Binding<Bool>, @ViewBuilder subviewByIndex: @escaping (Int) -> SubviewContent, @ViewBuilder rootView: @escaping () -> RootContent) {
        self._currentSubviewIndex = currentSubviewIndex
        self._showingSubview = showingSubview
        self.subviewByIndex = subviewByIndex
        self.rootView = rootView
    }
    
    private struct StackNavigationSubview<Content>: View where Content: View {
        
        @Binding var isVisible: Bool
        let contentView: () -> Content
        
        var body: some View {
            VStack {
                HStack { // Back button
                    Button(action: {
                        self.isVisible = false
                    }) {
                        Text("< Back")
                    }.buttonStyle(BorderlessButtonStyle())
                    Spacer()
                }
                .padding(.horizontal).padding(.vertical, 4)
                contentView() // Main view content
            }
        }
    }
}
struct ExampleView: View {
    
    @State private var currentSubviewIndex = 0
    @State private var showingSubview = false
    
    var body: some View {
        StackNavigationView(
            currentSubviewIndex: self.$currentSubviewIndex,
            showingSubview: self.$showingSubview,
            subviewByIndex: { index in
                self.subView(forIndex: index)
            }
        ) {
            VStack {
                Button(action: { self.showSubview(withIndex: 0) }) {
                    Text("Show View 1")
                }
                Button(action: { self.showSubview(withIndex: 1) }) {
                    Text("Show View 2")
                }
                Button(action: { self.showSubview(withIndex: 2) }) {
                    Text("Show View 3")
                }
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(Color.blue)
        }
    }
    
    private func subView(forIndex index: Int) -> AnyView {
        switch index {
        case 0: return AnyView(Text("I'm View One").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.green))
        case 1: return AnyView(Text("I'm View Two").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.yellow))
        case 2: return AnyView(VStack {
            Text("And I'm...")
            Text("View Three")
        }.frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.orange))
        default: return AnyView(Text("Inavlid Selection").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.red))
        }
    }
    
    private func showSubview(withIndex index: Int) {
        currentSubviewIndex = index
        showingSubview = true
    }
}