SwiftUI 入门教程 - NavigationStack

对于 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)
            }
        }
    }
}

效果图如下:

屏幕录制2023-08-18-15.39.43.gif

多个 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 的初始化方法中将其传递进去即可。

全部评论

相关推荐

10-17 16:07
门头沟学院 Java
牛牛大你18号:在汇报,突然弹出来,,领导以为我在准备跳槽,刚从领导办公室谈心出来
点赞 评论 收藏
分享
10-07 23:57
已编辑
电子科技大学 Java
八街九陌:博士?客户端?开发?啊?
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务