在本章中,你将学会使用模态弹窗完成页面跳转、自定义返回。
在上一章中,我们学习了使用NavigationView导航栏进行页面的跳转,这是常见的页面跳转的一种方式。
而另一种打开新页面的方式在iPhone中也很常见,就是从底部向上弹出一个新页面。
我们可以看到,这个页面又不完全是“进入”了一个新页面,它允许用户向下滑动关闭页面,这无疑大大增强了用户体验。
这时候给用户的感觉就是没有“打断”或者“干扰”用户的操作,并且完成了用户想做的事情。
本章节将分成3个部分讲解。
1、基于模态弹窗的页面跳转;
2、模态弹窗的自定义返回;
3、Alerts警告弹窗;
好了,说了那么多,我们开始吧。
第一部分:基于模态弹窗的页面跳转
首先,我们先创建一个新项目,命名为SwiftUIModalView。
我们尝试下简单的模态弹窗的跳转。
比如,我们在第一个页面创建一个按钮,当我们点击这个按钮时,打开一个模态弹窗页面。
如何创建按钮,可以了解下之前的文章。
创建按钮的代码如下:
//按钮 Button(action: { // 点击按钮跳转打开模态弹窗 }) { // 按钮样式 Text("打开模态弹窗") .font(.system(size: 14)) .frame(minWidth: 0, maxWidth: .infinity) .padding() .foregroundColor(.white) .background(Color(red: 51 / 255, green: 51 / 255, blue: 51 / 255)) .cornerRadius(5) .padding(.horizontal, 20) }
然后,我们需要再创建一个新的页面,方便我们实现从第一个页面点击按钮,以模态弹窗的方式打开第二个页面。
这里,我们基于上一章的内容,创建一个页面叫做DetailView。
在DetailView我们就放个文字简单说明下。
// 详情页 struct DetailView: View { var body: some View { Text("这是一个新页面") } }
接下来,我们实现下使用模态弹窗的跳转方法。
.sheet(isPresented: $showDetailView) { //要跳转的页面 } 复制代码
模态弹窗的方法很简单,使用.sheet修饰符。
isPresented是模态弹窗的触发条件,需要用$绑定一个操作,我们通常定义一个布尔值,它的初始状态为false。
@State var showDetailView = false 复制代码
当我们在第一个页面点击按钮时,按钮的操作就把这个布尔值变成true,那么就可以同时触发.sheet打开模态弹窗。
这里我们定义了一个叫做showDetailView的参数,它是bool类型,而且初始值为false。
当我们点击按钮时,showDetailView切换状态。
self.showDetailView.toggle()
我们点击模拟器上的Preview试下效果。
点击按钮后,我们可以看到系统打开了我们定义好的模态弹窗页面DetailView了。
完整代码如下:
import SwiftUI struct ContentView: View { @State var showDetailView = false var body: some View { // 按钮 Button(action: { // 点击按钮跳转打开模态弹窗 self.showDetailView.toggle() }) { // 按钮样式 Text("打开模态弹窗") .font(.system(size: 14)) .frame(minWidth: 0, maxWidth: .infinity) .padding() .foregroundColor(.white) .background(Color(red: 51 / 255, green: 51 / 255, blue: 51 / 255)) .cornerRadius(5) .padding(.horizontal, 20) } .sheet(isPresented: $showDetailView) { DetailView() } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } // 详情页 struct DetailView: View { var body: some View { Text("这是一个新页面") } }
第二部分:模态弹窗的自定义返回
在DetailView页面里,我们可以通过向下拖动页面,实现关闭页面的效果。
我们也可以尝试给DetailView加上一个关闭按钮,当我们点击关闭按钮时,也关闭这个页面。
还记得上一章我们学习过的NavigationView导航栏吗?我们可以给DetailView内容加上导航,然后导航右边加一个按钮操作。
// 详情页 struct DetailView: View { var body: some View { NavigationView { //主体内容 Text("这是一个新页面") .navigationBarItems(trailing: Button(action: { // 点击按钮关闭弹窗 }) { Image(systemName: "chevron.down.circle.fill") .foregroundColor(.gray) } ) } } }
好了,我们看到在DetailView导航栏右上角创建了一个新按钮。
那么接下来,我们要实现点击按钮,关闭弹窗。
这里我们有两种方法。
方法1:
和上一章NavigationView导航栏一样,创建一个环境变量:
@Environment(\.presentationMode) var presentationMode 复制代码
然后当我们点击按钮时,调用它的函数方法。
self.presentationMode.wrappedValue.dismiss() 复制代码
点击模拟器的Preview,我们发现实现了点击操作,关闭当前的模态弹窗页面。
完整代码如下:
// 详情页 struct DetailView: View { //定义环境变量 @Environment(\.presentationMode) var presentationMode var body: some View { NavigationView { //主体内容 Text("这是一个新页面") .navigationBarItems(trailing: Button(action: { // 点击按钮关闭弹窗 self.presentationMode.wrappedValue.dismiss() }) { Image(systemName: "chevron.down.circle.fill") .foregroundColor(.gray) } ) } } }
方法2:
也是之前的章节学习过 State状态和Binding绑定的使用。
我们可以在DetailView页面用@Binding绑定第一个页面创建的showDetailView布尔值。
//绑定参数 @Binding var showDetailView: Bool 复制代码
然后在DetailView页面,点击按钮操作时,将showDetailView的值切换。
self.showDetailView.toggle() 复制代码
最后在主页中.sheet跳转的目标页面绑定参数回来。
.sheet(isPresented: $showDetailView) { DetailView(showDetailView: $showDetailView) } 复制代码
这样,我们也可以实现页面的返回操作。
DetailView页面完整代码如下:
// 详情页 struct DetailView: View { //绑定参数 @Binding var showDetailView: Bool var body: some View { NavigationView { //主体内容 Text("这是一个新页面") .navigationBarItems(trailing: Button(action: { // 点击按钮关闭弹窗 self.showDetailView.toggle() }) { Image(systemName: "chevron.down.circle.fill") .foregroundColor(.gray) } ) } } }
那么两种方法有什么不同呢?
第一种方法简单来说,是“撤销”原有的操作。
而第二种绑定的方式,是反向传递参数值给到第一个页面。
两种方式各有好处,第二种方法的好处是如果第二个页面返回的时候需要带参数值回来,那么我们可以通过绑定的方式将DetailView的值给回到第一个页面。
第三部分:Alerts警告弹窗
在模态弹窗中,还有一种类型叫做Alerts警告弹窗,也属于模态弹窗的一种。
我们在App也经常见过它,当我们确定要付款时,或者触发到有风险的操作时,系统就会打开Alerts警告弹窗。
Alerts警告弹窗一种二次确认的弹窗,常用于系统风险提醒、是否立即执行等场景。
创建警告弹窗的方法和创建一般的模态弹窗方法一样,只是参数不一样。
.alert(isPresented: $showAlert) { //Alerts结构体 }
我们还是使用isPresented触发,我们定义一个变量showAlert的状态,初始状态是false。
@State var showAlert = false
与创建标准模态弹窗不同的是,.alert里面的内容是Alerts结构体,也就是标准的警告弹窗。
我们使用Alert结构体来创建警告弹窗。
Alert(title: Text("这是弹窗标题"), message: Text("这是弹窗的内容"), primaryButton: .default(Text("确定")), secondaryButton: .cancel(Text("取消")))
基本了解了警告弹窗的用法,让我们实操试试吧。
我们把DetailView页面的文字改成“打开警告弹窗”,然后把它变成按钮的形式。
以便于我们点击文字按钮,实现打开警告弹窗的效果。
//主体内容 Button(action: { // 点击按钮打开警告弹窗 }) { Text("打开警告弹窗") }
然后我们将警告弹窗的方法写到DetailView页面里面,方法和主页中.sheet的方法类似。
先定义一个变量showAlert,初始值为false,当按钮点击的时候,showAlert的状态切换。
在Text按钮外边(注意位置),使用.alert的创建一个警告弹窗,然后在警告弹窗内容里填充Alerts结构体代码。
这样就完成了Alerts警告弹窗的创建。
DetailView完整代码如下:
// 详情页 struct DetailView: View { // 绑定参数 @Binding var showDetailView: Bool @State var showAlert = false var body: some View { NavigationView { // 主体内容 Button(action: { // 点击按钮打开警告弹窗 self.showAlert.toggle() }) { Text("打开警告弹窗") } .alert(isPresented: $showAlert) { //Alerts结构体 Alert(title: Text("这是弹窗标题"), message: Text("这是弹窗的内容"), primaryButton: .default(Text("确定")), secondaryButton: .cancel(Text("取消"))) } .navigationBarItems(trailing: Button(action: { // 点击按钮关闭弹窗 self.showDetailView.toggle() }) { Image(systemName: "chevron.down.circle.fill") .foregroundColor(.gray) } ) } } }
快来动手试试吧!