List的导航或者页面按钮的导航是iOS中最常见的情况,从OC的UIKit开始 UINavigationController就是最常用的,每次公司新业务 开一个新的页面或者首页加功能都是从UINavigationController开始
历史 -- 视图导航
-
1 开始的时候从xib ,tab + nav
-
2 OC 的正常使用UINavigationController
-
3 router path 的方式,通过runtime 和 hashmap来控制
其他的方式 大部分围绕去耦合的方式,少import 的思想来设计视图导航控件。这一次苹果自己设计了一次
NavigationStack 基本用法
NavigationStack {
List(parks) { park in
NavigationLink(park.name, value: park)
}
.navigationDestination(for: Park.self) { park in
ParkDetails(park: park)
}
}
NavigationStack 等同于开始的首页navContrller ,导航开始的时候。
@State private var path: [File] = []
NavigationStack(path: $path) {}
这个还有一种方式 通过path 来记录自己路径一个@State 状态变化时刻观察
这里参考 Simon Ng 的demo 懒得new 一个新的
全代码
var body: some View {
NavigationStack {
List(bgColors, id: \.**self**) { bgColor **in**
NavigationLink {
bgColor
.frame(maxWidth: .infinity, maxHeight: .infinity)
} label: {
Text(bgColor.description)
}
}
.listStyle(.plain)
.navigationTitle("Color")
}
}
NavigationLink
其实是个view ,用NavigationLink包一个自己的Cell在Label变量里面,这个很重要,这个很重要,
这个很重要。因为不是所有列表都要跳转,但是这个列表还有部分需要跳转。
NavigationLink 携带数值
NavigationStack {
List(bgColors, id: \.self) { bgColor in
NavigationLink(value: bgColor) {
Text(bgColor.description)
}
}
.listStyle(.plain)
.navigationDestination(for: Color.self) { color in
color
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
.navigationTitle("Color")
}
Link 的value 和 navigationDestination 的for 类型是对应的,不一定 navigationDestination 必须有才能跳转,仅仅是个一个选项
navigationDestination
具体页面在这里实现。也可以多个Link 来一一对应 多个 navigationDestination
var body: some View {
NavigationStack {
List {
Section("Categories") {
ForEach(categories) { category in
NavigationLink(value: category) {
Text(category.query)
.font(.headline)
}
}
}
Section("Recent") {
ForEach(recentProducts) { product in
NavigationLink(product.title, value: product)
}
}
}
.navigationTitle("Home")
.navigationDestination(for: Category.self) { category in
CategoryView(category: category)
}
.navigationDestination(for: Product.self) { product in
ProductDetailView(product: product)
}
}
这里参考 Swift with Majid 的文章的代码。也是懒得敲一遍了。
不同的数据,不同的跳转新页面,别yy 非页面跳转的情况,比如一个变量一个 刷新什么的。
因为 navigationDestination 的文档说明
func navigationDestination<D, C>(for data: D.Type, destination: @escaping (D) -> C) -> some View where D : Hashable, C : View
内部要的是一个view,不是view 哪怕是写一个print 都是错误
连续跳转
这个我的理解和Simo Ng 的文章不同的看法
NavigationStack 要的去耦合 ,新页面如果再想跳不停的重复写Link 就行,不用写 navigationDestination 和 NavigationStack(这个和UINavigationController 的思想一样),一个控制器 控制所有压入的page,不用每个page 都有一个nav。
但是因为引入的 navigationDestination 统一管理,是好处也是难处。很少业务不停的push 不需要改一些数据问题。
所以反而不用navigationDestination 能适应的场景更多,这样的写法也更简单
NavigationStack {
List(bgColors, id: \.**self**) { bgColor **in**
NavigationLink { // 跳转后的page
bgColor
.frame(maxWidth: .infinity, maxHeight: .infinity)
} label: { // cell的样子
Text(bgColor.description)
}
}
.listStyle(.plain)
.navigationTitle("Color")
}
别直接 的就 NavigationLink(value: category) { },这样少了很多的麻烦
这个的版本控制 一定要注意,mac 和ios 的都是比较新的版本才适配,老的navigationView 已经放弃
吐槽
juejin 的md 太难用了,代码格式 不能直接复制粘贴。iOS 的NavigationStack 虽然多平台都可以用,但是macos 用的更多的是 NavigationSplitView 来进行 ui 的分布控制。
遇到的坑
这个最大的坑就是 push 的时候 如果不是一个View 就全要从新考虑替换掉Link 的写法,这也是SwiftUI和UIKit 的思想不一样的原因,View的编写用SwiftUI 效率是很高,UIKit的navigation 放开了点击的事件,但是SwiftUI 想的是尽量不要在view 里面写方法关于逻辑的,这个事写SwiftUI的一个个人感觉
入口和出口对于SwiftUI 都是一个简单的变量,可以 @State 也可能是一个@Binding 变量。但是绝对不是一个Bool var + 一个刷新方法放在nav 里面