在本章中,你将学会如何使用NavigationView构建基础的导航栏,以及基于导航栏的页面跳转。
如果你恰好用过UIkit,应该尝试过用storyboard或者UINavigationController来构建页面导航。
而在SwiftUI中,我们使用NavigationView,而它的使用方法和上一章List基本一样。
本章节将分成3个部分讲解。
1、构建一个简单的导航栏;
2、基于导航栏的页面跳转;
3、导航栏自定义返回;
第一部分:构建一个简单的导航栏
我们先尝试在原来的List上增加NavigationView看看导航栏的效果。
UI稿如下:
首先,我们先创建一个新项目,命名为SwiftUINavigationView。
然后,我们把上一章的代码拿过来作为示例讲解。
代码如下:
import SwiftUI struct ContentView: View { // 定义数组,存放数据 var Messages = [ Message(name: "这是微信", image: "weixin"), Message(name: "这是微博", image: "weibo"), Message(name: "这是QQ", image: "qq"), Message(name: "这是电话", image: "phone"), Message(name: "这是邮箱", image: "mail") ] var body: some View { // 列表 List(Messages) { Message in HStack { Image(Message.image) .resizable() .frame(width: 40, height: 40) .cornerRadius(5) Text(Message.name) } } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } struct Message: Identifiable { var id = UUID() var name: String var image: String }
NavigationView的构建和List方法一样,将我们需要的内容包裹在NavigationView里面就行了。
NavigationView{ } 复制代码
这里注意的是,需要把整个List包裹起来。
包裹完成后,我们可以看到整个List顶部留出了导航栏的位置。
//导航栏 NavigationView{ // 列表 List(Messages) { Message in HStack { Image(Message.image) .resizable() .frame(width: 40, height: 40) .cornerRadius(5) Text(Message.name) } } }
我们尝试加个标题,这里我们用的修饰符是:
.navigationBarTitle("我是标题") 复制代码
修饰符需要加在内容最外层,而不是NavigationView外层。
这样,我们就得到了一个拥有大标题的列表。
//导航栏 NavigationView { // 列表 List(Messages) { Message in HStack { Image(Message.image) .resizable() .frame(width: 40, height: 40) .cornerRadius(5) Text(Message.name) } }.navigationBarTitle("我是标题") }
是不是挺简单!
SwiftUI将很多事情都简单化了,以至于我们在使用不同的控件的方法基本都差不多。
第二部分:基于导航栏的页面跳转
下面进阶一下。
我们尝试从一个页面跳转到第二个页面,并且还能返回。
UI稿如下:
我们先完成第二个页面的内容,然后再从第一个页面点击对应的列表进入第二个页面。
我们在ContentView页面最后创建一个新的页面,命名为DetailView。
代码如下:
//详情页面 struct DetailView: View { var message: Message var body: some View { VStack { Image(message.image) .resizable() .frame(width: 80, height: 80) Text(message.name) .font(.system(.title, design: .rounded)) .fontWeight(.black) Spacer() } } } 复制代码
我们在DetailView里面引用Message数组的数据,将Image图片和Text文字换成数组的参数。
这样我们就可以第一个页面点击哪一个列表,然后就能将对应的图片和文字带入到第二个页面,也就是所谓的传参。
然后回到第一个页面里。
我们需要点击List列表,然后跳转到第二个页面。
这时候我们需要使用一个新的参数,叫做NavigationLink。
NavigationLink(destination: DetailView()) { //点击跳转的内容 }
destination表明我们要跳转的页面,这里我们需要跳转的页面是DetailView。
我们需要点击List里面的一行,然后跳转到第二个页面,因此NavigationLink需要放在List里面,而不是包裹住整个List。
如果NavigationLink包裹住List,那么就变成了点击整个List跳转了,这里我们需要的是点击List单独一行对应跳转。
NavigationView { // 列表 List(Messages) { Message in NavigationLink(destination: DetailView(message: Message)) { HStack { Image(Message.image) .resizable() .frame(width: 40, height: 40) .cornerRadius(5) Text(Message.name) } } }.navigationBarTitle("我是标题") }
我们可以看到,跳转的目标是DetailView,并且我们把Message结构体的参数传递给了DetailView页面的message变量。
这样就实现了我们Message结构体里的参数传递给message,也就实现了,我们点击的Message是哪一个,DetailView页面的message对应传递哪一个参数。
我们点击模拟器上面的Preview运行下模拟器,尝试点击List其中一行,就可以体验下点击跳转页面,再点击返回到主页的效果。
科普一个知识点。
我们在常用的App当中看到的顶部导航栏文字是居中的,这是怎么实现的呢?
也很简单,ios默认的是大标题效果(.automatic),也就是:
.navigationBarTitle("我是标题", displayMode: .automatic) 复制代码
我们只需要给.navigationBarTitle("我是标题”)里加入参数控制(.inline),就可以实现文字标题居中效果。
.navigationBarTitle("我是标题", displayMode: .inline)
好了,至此我们就完成了基于导航栏的页面跳转方式啦!
第三部分:导航栏自定义返回
接下来,让我们看看DetailView页面,我们会发现,这个“返回”的操作似乎没那么好看。
很多时候,我们的“返回”操作可能是一个图标按钮,也可能是“文字”按钮。
我们有没有办法美化下这个返回首页的操作?
让我们分析下。
我们只需要把系统自带的返回操作隐藏,然后再自己“写”一个返回操作就可以了。
这里我们用到了隐藏导航返回按钮的参数:
.navigationBarBackButtonHidden(true)
下一步,我们自己写一个返回的按钮,在这里,我们需要用到另一个参数:
.navigationBarItems(leading: Button(action : { // 点击按钮后的操作 }){ //按钮及其样式 Image(systemName: "chevron.left") .foregroundColor(.gray) }) 复制代码
我们试试用图标按钮作为返回按钮。
这里使用的是系统自带的图片,填充颜色为灰色。
运行看看,我们可以点击主页列表数据进入详情页。
但是,我们点击返回操作没有反应。
这是因为我们还没有实现返回的方法。
SwiftUI提供了(.presentationMode)内置环境值,我们可以用这个环境值实现返回到前一个视图的操作。
@Environment(\.presentationMode) var mode 复制代码
然后在返回按钮的点击操作时调用环境值的dismiss()函数,就可以实现返回的操作。
self.mode.wrappedValue.dismiss() 复制代码
DetailView页面完整代码如下:
// 详情页面 struct DetailView: View { //环境值 @Environment(\.presentationMode) var mode var message: Message var body: some View { VStack { Image(message.image) .resizable() .frame(width: 80, height: 80) Text(message.name) .font(.system(.title, design: .rounded)) .fontWeight(.black) Spacer() } .navigationBarBackButtonHidden(true) .navigationBarItems(leading: Button(action : { // 点击按钮后的操作 self.mode.wrappedValue.dismiss() }){ //按钮及其样式 Image(systemName: "chevron.left") .foregroundColor(.gray) }) } }
运行下代码,我们发现实现自定义按钮的返回操作啦!
好了,今天的知识点就到这里了。