注意NavigationView已经废弃替代品是NavigationStack。目录NavigationView 标题和按钮标题显示模式导航栏按钮注意实时预览可能没有反应实现页面导航NavigationLink完整导航页面示例导航嵌套嵌套视图的标题技巧用Spacer使Stack最大化View用作参数并给View传递参数自定义返回按钮NavigationView 标题和按钮导航视图指的是顶部的一两行区域称为顶部导航或导航栏。顶部一般会包括页面标题和导航按钮下面的示例是基本的用法struct SwiftUIViewNavigation: View { var body: some View { NavigationView(){ VStack{ Text(Hello, World!) Spacer() Text(Hello, World!) } .navigationBarTitle(123,displayMode: .inline)//标记1 .navigationBarItems(trailing: titleLineView)//标记2 .navigationBarItems(leading: titleLineView, trailing: titleLineView)//标记3 } } private var titleLineView: some View{ Button(action:{}){ VStack{ Image(systemName: square.and.arrow.up) Image(systemName: square.and.arrow.up) } } } }代码中关键三行代码做了标注分别设置了标题、显示方式、前后按钮。注意这些修饰是在NavigationView的内部进行的如果有多个navigationBarTitle()设置了不同的标题实测内层的生效而示例中连用两个navigationBarItems的效果是叠加。上面代码的效果标题显示模式上面的代码设置显示模式为inline标题和按钮会显示在同一行如果改为automatic或large则效果为可以注意到分成了两行标题独占一行。导航栏按钮导航栏前后按钮都是视图上面的代码用了一个稍微复杂的视图演示了视图超出导航栏大小时的效果。上面的代码用VStack组合了两个图标超出了导航栏高度所以显示不全。正常情况应该用HStack来组合多个按钮下面的代码增加了绑定来显示哪个按钮被点击struct SwiftUIViewNavigation: View { State var info : String info var body: some View { NavigationView(){ VStack{ Text(info) Spacer() Text(Hello, World!) } .navigationBarTitle(123,displayMode: .automatic) .navigationBarItems(trailing: titleLineView) .navigationBarItems(leading: titleLineView, trailing: titleLineView) } } private var titleLineView: some View{ HStack{ Button(action:{infoa}){ Image(systemName: square.and.arrow.up.fill) } Button(action:{infob}){ Image(systemName: square.and.arrow.up) } } } }点击效果注意实时预览可能没有反应今天修改代码的时候实时预览经常出问题要多些改动实时预览才会生效敲一些空格回车。实现页面导航NavigationLinkNavigationLink可以实现跳转需要两个参数标签和跳转目标视图当然标签也是个视图struct NavigationLinkLabel, Destination where Label : View, Destination : View用法很简单标签可以用字符串视图可以是已经做好的任何页面。完整导航页面示例下面是一个完整的导航页面的例子里面包含了一些布局和模块化代码的技巧。import SwiftUI struct SwiftUIViewNavigation: View { State var info: String info var body: some View { NavigationView { HStack { VStack(alignment: .leading, spacing: 20) { VStack(alignment: .leading, spacing: 20) { MenuItemView(imageName: person, itemName: 账号设置){ InputView() } MenuItemView(imageName: person, itemName: 账号设置){ InputView() } MenuItemView(imageName: person, itemName: 账号设置){ InputView() } Spacer() } .navigationBarTitle(导航, displayMode: .inline) .navigationBarItems( leading: titleLineViewLeft, trailing: titleLineViewWright ) HStack { Text(info).padding(10) Spacer() }.background(.cyan) } .padding(.all, 20) Spacer() }.border(.red) } } struct MenuItemViewdestinationView: View: View { var imageName: String var itemName: String ViewBuilder public var destinationview: () - destinationView var body: some View { NavigationLink(destination: destinationview) { HStack(spacing: 20) { Image(systemName: imageName) Text(itemName) } } } } private var titleLineViewLeft: some View { HStack { Button(action: { info 返回 }) { Image(systemName: chevron.backward) } } } private var titleLineViewWright: some View { HStack { Button(action: { info 搜索 }) { Image(systemName: magnifyingglass) } Button(action: { info 分享 }) { Image(systemName: square.and.arrow.up) } } } }效果三个导航链接是一样的点击之后是InputView 视图代码是这样的import SwiftUI struct InputView: View { State var texta\r\nb var body: some View { VStack { Text(\(text)) .padding() .frame(width: 300,height: 100) .border(.black,width: 5) .multilineTextAlignment(.leading) TextEditor(text:$text) .padding() .frame(width: 300,height: 100) .border(.black,width: 5) TextField(Hello, World!,text:$text) .padding() .frame(width: 300,height: 100) .border(.black,width: 5) } } } #Preview { InputView() }独立的预览效果是这样的通过导航进入和独立页面的区别是上面有个返回按钮和导航页我们自己做的图标看起来是一样的但是这个是系统提供的点击返回按钮可以回到导航页面。导航嵌套前面使用的InputView是个简单页面如果换成另一个导航页面会怎么样将导航目标替换为自身MenuItemView(imageName: person, itemName: 账号设置){ SwiftUIViewNavigation() }效果多点几次非常明显导航效果是嵌套的目标页面完整嵌套在子视图区域。嵌套视图的标题嵌入当然也应该有自己的标题。之前我们已经知道多次设置navigationBarTitle内层的生效嵌套的就处于内层所以前台页面的设置会替代导航页面的设置。给InputView视图加上navigationBarTitle设置struct InputView: View { State var texta\r\nb var body: some View { VStack { 。。。。。。 } .navigationBarTitle(InputView, displayMode: .inline) } }注意这里设置了displayMode这是不会改变导航页的显示布局的。也就是说如果设置成large或自动而导航页面是inline由于嵌套视图的位置已经确定并没有留出large的显示位置嵌套视图的标题会被遮盖从而无法看到。正常的显示效果技巧用Spacer使Stack最大化HStack和VStack默认不是尽可能大的内部子视图对齐方式只能在有效范围内对齐而不是我们期待的整个屏幕。当我们想实现基于屏幕的靠左或靠右时需要先把Stack最大化。frame是一个办法但是非常不理想通过嵌套一个H/VStack加上Spacer是最直白的。View用作参数并给View传递参数View大量用作参数包括很多习惯上是个字符串的其实也是View参数比如导航链接的标签参数。我们前面已经用过不带参数的子视图非常简单直接构造一个View即可private var titleLineViewLeft: some View { HStack { Button(action: { info 返回 }) { Image(systemName: chevron.backward) } } }但是需要参数化的视图就比较麻烦因为内部实现对视图渲染有要求。代码可以照下面的葫芦来画瓢struct MenuItemViewdestinationView: View: View { var imageName: String var itemName: String ViewBuilder public var destinationview: () - destinationView var body: some View { NavigationLink(destination: destinationview) { HStack(spacing: 20) { Image(systemName: imageName) Text(itemName) } } } } 调用 MenuItemView(imageName: person, itemName: 账号设置){ InputView() }视图参数如果有多个排在第一个的是默认的后面的都需要名字加冒号再加大括号。自定义返回按钮打开的新视图嵌套在导航框架里具有一个标准的返回按钮。我们可以隐藏这个按钮并替换成我们自己的视图。修改InputViewstruct InputView: View { Environment(\.presentationMode) var presentationMode //用来实现返回的环境值 State var texta\r\nb var body: some View { VStack { 。。。。。。 } .navigationBarTitle(InputView, displayMode: .inline) .navigationBarBackButtonHidden() //隐藏默认返回按钮 .navigationBarItems(leading: titleLineViewLeft) //添加自定义返回按钮 } //自定义返回按钮 private var titleLineViewLeft: some View { HStack { Button(action: { self.presentationMode.wrappedValue.dismiss()}) { Image(systemName: chevron.backward) } } } }因为我们用的图标和系统是一样的看不出区别所以可以屏蔽掉.navigationBarBackButtonHidden()看看效果出现了两个一模一样的返回按钮说明代码生效了。此时我们还可以试一下侧滑返回是有效的。我们再把.navigationBarBackButtonHidden()这句放出来默认返回按钮就没有了但是侧滑返回也没有了。当然有办法用代码实现侧滑返回不过如果不是游戏应用有点吃饱了撑的。