
目录
主控界面
控制变量的传递
欢迎界面
登录界面
主界面
带参数视图的预览
应用导航结构大致是这样的:欢迎界面(一般是为了隐藏后台加载数据过程)、登录界面、主界面这样的关系。
我们已经知道了导航视图和选项卡视图,但是欢迎界面和登录界面并不是适合这两种控制结构,因为欢迎界面和登录界面使用过就能再回去了,所以需要不同的方式来实现:if else 替换视图。
首先我们要做好几个视图:WelcomeView、LoginView和主界面SwiftUIViewNavigation(为了不影响当前关注点,具体代码放在后面)。
主控界面
然后我们来做主控界面:
import SwiftUI
struct MainView: View {
@State private var isWelcome = true
@State private var isLoggedIn = false
var body: some View {
//NavigationView {
if isWelcome {
WelcomeView(isWelcome: $isWelcome)
} else if isLoggedIn {
SwiftUIViewNavigation(isLoggedIn:$isLoggedIn)
} else {
LoginView(isLoggedIn: $isLoggedIn)
}
//}
}
}
主控界面逻辑很清楚,根据两个变量来控制显示哪个界面,最外层的NavigationView被我屏蔽了,因为以为需要内嵌导航链接(NavigationLink不能在没有NavigationView的情况下工作),但是实际上没用到。
我们的逻辑是初始状态进入欢迎界面,欢迎界面有个按钮,点一下修改变量值,从而引发主控界面改变,进入到登录界面,登录后进入主界面。
控制变量的传递
@State变量仅在视图内有效,想在不同视图内共享变量,需要使用@Binding变量,@Binding变量需要作为参数在视图构造的时候传入。
相当于c/c++的extern。
欢迎界面
欢迎界面通常做成选项卡,并且有个“立即体验”按钮。我个人非常不能理解“立即体验”的含义。示例代码:
struct WelcomeView: View {
@Binding var isWelcome: Bool //绑定变量,需要外部传入
var body: some View {
HStack {
Spacer()
VStack {
Spacer()
TabView{
Text("You are welcome")
Text("You are welcome")
Text("You are welcome")
}
.tabViewStyle(.page)
.indexViewStyle(.page(backgroundDisplayMode: .always))
Button(action: {
isWelcome = false //修改绑定变量,触发视图重绘
}) {
Image(systemName: "person")
Text("跳过")
}
Spacer()
}
Spacer()
}
.border(.red)
}
}
核心代码就两句,代码里做了注释。效果:

点一下最下面的按钮就可以进入登录界面。
登录界面
登录界面要点完全一样,传入变量,修改变量,触发进入主界面:
struct LoginView: View {
@Binding var isLoggedIn: Bool
@State var username: String = ""
var body: some View {
HStack {
Spacer()
VStack {
Spacer()
VStack(alignment:.leading){
Text("You need login")
TextField("username", text: $username)
Button(action: {
isLoggedIn = true
}) {
Image(systemName: "person")
Text("Login")
}
}.padding()
Spacer()
}
Spacer()
}
.border(.red)
}
}
注意里面有个TextField,可以输入内容,可以用来观察页面跳转的时候视图的内容是否会被保留(也就是视图对象是否被重新创建)。

主界面
主界面也需要绑定参数,因为一般会有一个注销按钮,导致程序回到登录界面:
struct SwiftUIViewNavigation: View {
@Binding var isLoggedIn: Bool
@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: "嵌套SwiftUIViewTab"
) { SwiftUIViewTab() }
MenuItemView(
imageName: "person",
itemName: "嵌套SwiftUIViewNavigation"
) {
SwiftUIViewNavigation(isLoggedIn:$isLoggedIn)
}
Spacer()
Button(action: {
isLoggedIn = false
}) {
Image(systemName: "person")
Text("logout")
}
}
//.navigationBarTitle("导航", displayMode: .large)
//.navigationBarItems(leading: titleLineViewLeft,trailing: titleLineViewWright)
HStack {
Text(info).padding(10)
Spacer()
}.background(.cyan)
}
.padding(.all, 20)
Spacer()
}.border(.red)
}
}
struct MenuItemView<destinationView: 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: "chevron.backward")
}
Button(action: { info = "搜索" }) {
Image(systemName: "magnifyingglass")
}
Button(action: { info = "分享" }) {
Image(systemName: "square.and.arrow.up")
}
}
}
}
#Preview {
var isLoggedIn : Bool = true
SwiftUIViewNavigation(isLoggedIn:Binding.constant(isLoggedIn))
}
注意主界面有个注销按钮,点一下会导致回到登录界面。

在登录界面输入信息,在主界面退出登录回到登录界面,发现输入的信息没有了,说明视图切换后原来的视图对象就不存在了,程序必须自己保存和恢复数据。
带参数视图的预览
前面主界面的预览代码和原始代码不同,增加了参数传递。预览和运行的机制并不相同,绑定变量是个常量,修改是无效的(当然这里也不影响我们的功能)。
代码就是个套路:
#Preview {
var isLoggedIn : Bool = true
SwiftUIViewNavigation(isLoggedIn:Binding.constant(isLoggedIn))
}

