关于 iOS 开发者来说,导航视图无疑是最常用的组件之一。当 SwiftUI 首次发布时,官方提供了 NavigationView 视图,以供开发人员构建根据导航的用户界面。

跟着 iOS16 的发布,NavigationView 现已被苹果官方弃用,并引入了一个名为 NavigationStack 的新视图来出现视图仓库。最重要的是,开发者能够利用这个新视图来构建数据驱动的导航。

NavigationView 的运用办法

在 iOS16 之前,咱们能够运用 NavigationView 加 NavigationLink 来进行导航栏的显现以及导航跳转:

var body: some View {
    NavigationView {
        NavigationLink {
            Text("概况页")
        } label: {
            Text("去概况")
        }
    }
}

上述代码创建了一个带有导航控制器的视图,而且带有《去概况》的一个按钮。点击该按钮能够导航到概况页面。

NavigationStack 的运用办法

运用 NavigationStack 在根视图上显现视图仓库。用户能够通过点击 NavigationLink 将视图添加到视图栈的顶部,或许运用撤退按钮或滑动手势来删去视图。

视图栈总是显现栈顶的视图,而且根视图是不能被删去的。

咱们能够运用 navigationDestination(for:destination:) 修饰符将视图与相关联的数据进行绑定,然后初始化一个 NavigationLink 来进行导航跳转。

假定咱们要实现这样一个需求:主页显现猫咪的列表,点击每一条会跳转到概况页。

首要,定义一个结构体用来存储猫咪的数据:

struct Cat: Identifiable, Hashable {
    let name: String
    let id: UUID
}

由于 List 对每一条数据要求唯一性,所以咱们的结构体要恪守上述的两个协议。

接着,创建一个名为 CatDetailView 的视图来表示概况页,编写以下代码:

struct CatDetailView: View {
    let cat: Cat
    var body: some View {
        Text(cat.name)
    }
}

最后,便是创建一个名为 CatListView 的视图,用来表示列表页,编写以下代码:

struct CatListView: View {
    let cats = [Cat(name: "red cat", id: UUID()),
    Cat(name: "black cat", id: UUID()),
    Cat(name: "orange cat", id: UUID())]
    var body: some View {
        NavigationStack {
            List(cats) { cat in
                NavigationLink(cat.name, value: cat)
            }
            .navigationDestination(for: Cat.self) { cat in
                CatDetailView(cat: cat)
            }
        }
    }
}

效果图如下:

SwiftUI 入门教程 - NavigationStack

多个 Navigation Destination 修饰符

开发者能够定义多个 navigationDestination 修饰符来处理不同类型的导航链接。在前面的比方中咱们处理了类型为 Cat 的导航处理。假定咱们需要在主页加一种类型为 Dog 的导航处理,能够直接在后面再加一个 navigationDestination。比方下面的代码:

NavigationStack {
	List(cats) { cat in
	    NavigationLink(cat.name, value: cat)
	}
	List(dogs) { dog in
	    NavigationLink(dog.name, value: dog)
	}
	.navigationDestination(for: Cat.self) { cat in
	    CatDetailView(cat: cat)
	}
	.navigationDestination(for: Dog.self) { dog in
	    DogDetailView(dog: dog)
	}
}

Tips: DogDetailView 与 Dog 皆与猫咪的类似,仅改动一下名字。冗余代码就不在此贴出了。

导航栏的状况管理

与之前的 NavigationView 不同,新的 NavigationStack 能够方便地盯梢导航状况。NavigationStack 视图有另一个初始化办法,它接受一个path参数,该参数绑定到仓库的导航状况: public init(path: Binding<Data>, @ViewBuilder root: () -> Root)

示例代码如下:

@State private var presentedCats: [Cat] = []
var body: some View {
    NavigationStack(path: $presentedCats) {
        List(cats) { cat in
            NavigationLink(cat.name, value: cat)
        }
        .navigationDestination(for: Cat.self) { cat in
            VStack {
                Text("\(presentedCats.count), \(presentedCats.description)")
                CatDetailView(cat: cat)
            }
        }
    }
}

首要声明了一个 State 的属性用来保存当时导航的状况,然后在 NavigationStack 的初始化办法中将其传递进去即可。