Hus*_*r28 16 navigation macos swiftui macos-catalina swiftui-navigationview
我正在尝试为我的 macOS SwiftUI 状态栏应用程序创建一个设置视图。到目前为止,我的实现一直使用NavigationView, 和NavigationLink,但是当设置视图将父视图推到一边时,这个解决方案会产生一个半视图。下面的屏幕截图和代码示例。
导航边栏
struct ContentView: View {
var body: some View {
VStack{
NavigationView{
NavigationLink(destination: SecondView()){
Text("Go to next view")
}}
}.frame(width: 800, height: 600, alignment: .center)}
}
struct SecondView: View {
var body: some View {
VStack{
Text("This is the second view")
}.frame(width: 800, height: 600, alignment: .center)
}
}
Run Code Online (Sandbox Code Playgroud)
我能找到的少量信息表明,在 macOS 上使用 SwiftUI 是不可避免的,因为NavigationViewiOS ( StackNavigationViewStyle)上的“全屏”在 macOS 上不可用。
在 SwiftUI for macOS 中,是否有一种简单甚至复杂的方法来实现到设置视图的转换,该视图占据整个框架?如果没有,是否可以使用AppKit用来调用用 SwiftUI 编写的 View 对象?
也是一个 Swift 新手 - 请保持温柔。
Asp*_*eri 12
这是自定义导航类解决方案的可能方法的简单演示。使用 Xcode 11.4 / macOS 10.15.4 测试
注意:背景颜色用于更好的可见性。
struct ContentView: View {
@State private var show = false
var body: some View {
VStack{
if !show {
RootView(show: $show)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.blue)
.transition(AnyTransition.move(edge: .leading)).animation(.default)
}
if show {
NextView(show: $show)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.green)
.transition(AnyTransition.move(edge: .trailing)).animation(.default)
}
}
}
}
struct RootView: View {
@Binding var show: Bool
var body: some View {
VStack{
Button("Next") { self.show = true }
Text("This is the first view")
}
}
}
struct NextView: View {
@Binding var show: Bool
var body: some View {
VStack{
Button("Back") { self.show = false }
Text("This is the second view")
}
}
}
Run Code Online (Sandbox Code Playgroud)
The*_*eil 12
我扩展了Asperi的伟大建议,并StackNavigationView为 macOS(甚至 iOS,如果你愿意的话)创建了一个通用的、可重用的。一些亮点:
斯威夫特 v5.2:
\nstruct StackNavigationView<RootContent, SubviewContent>: View where RootContent: View, SubviewContent: View {\n \n @Binding var currentSubviewIndex: Int\n @Binding var showingSubview: Bool\n let subviewByIndex: (Int) -> SubviewContent\n let rootView: () -> RootContent\n \n var body: some View {\n VStack {\n VStack{\n if !showingSubview { // Root view\n rootView()\n .frame(maxWidth: .infinity, maxHeight: .infinity)\n .transition(AnyTransition.move(edge: .leading)).animation(.default)\n }\n if showingSubview { // Correct subview for current index\n StackNavigationSubview(isVisible: self.$showingSubview) {\n self.subviewByIndex(self.currentSubviewIndex)\n }\n .frame(maxWidth: .infinity, maxHeight: .infinity)\n .transition(AnyTransition.move(edge: .trailing)).animation(.default)\n }\n }\n }\n }\n \n init(currentSubviewIndex: Binding<Int>, showingSubview: Binding<Bool>, @ViewBuilder subviewByIndex: @escaping (Int) -> SubviewContent, @ViewBuilder rootView: @escaping () -> RootContent) {\n self._currentSubviewIndex = currentSubviewIndex\n self._showingSubview = showingSubview\n self.subviewByIndex = subviewByIndex\n self.rootView = rootView\n }\n \n private struct StackNavigationSubview<Content>: View where Content: View {\n \n @Binding var isVisible: Bool\n let contentView: () -> Content\n \n var body: some View {\n VStack {\n HStack { // Back button\n Button(action: {\n self.isVisible = false\n }) {\n Text("< Back")\n }.buttonStyle(BorderlessButtonStyle())\n Spacer()\n }\n .padding(.horizontal).padding(.vertical, 4)\n contentView() // Main view content\n }\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n有关所用泛型的更多信息可以在此处@ViewBuilder找到。
这是它的基本使用示例。父视图跟踪当前选择和显示状态(使用@State),允许其子视图内的任何内容触发状态更改。
struct ExampleView: View {\n \n @State private var currentSubviewIndex = 0\n @State private var showingSubview = false\n \n var body: some View {\n StackNavigationView(\n currentSubviewIndex: self.$currentSubviewIndex,\n showingSubview: self.$showingSubview,\n subviewByIndex: { index in\n self.subView(forIndex: index)\n }\n ) {\n VStack {\n Button(action: { self.showSubview(withIndex: 0) }) {\n Text("Show View 1")\n }\n Button(action: { self.showSubview(withIndex: 1) }) {\n Text("Show View 2")\n }\n Button(action: { self.showSubview(withIndex: 2) }) {\n Text("Show View 3")\n }\n }\n .frame(maxWidth: .infinity, maxHeight: .infinity)\n .background(Color.blue)\n }\n }\n \n private func subView(forIndex index: Int) -> AnyView {\n switch index {\n case 0: return AnyView(Text("I\'m View One").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.green))\n case 1: return AnyView(Text("I\'m View Two").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.yellow))\n case 2: return AnyView(VStack {\n Text("And I\'m...")\n Text("View Three")\n }.frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.orange))\n default: return AnyView(Text("Inavlid Selection").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.red))\n }\n }\n \n private func showSubview(withIndex index: Int) {\n currentSubviewIndex = index\n showingSubview = true\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n注意:像这样的泛型要求所有子视图都属于同一类型。如果不是这样,您可以将它们包装在 中AnyView,就像我在这里所做的那样。AnyView如果您对所有子视图使用一致的类型,则不需要包装器(根视图\xe2\x80\x99s 类型不需要匹配\xe2\x80\x99s 类型)。