SwiftUI 关于NavigationStack 视图导航

3,407 阅读3分钟

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 一个新的

iOS 版本

mac 版本

全代码


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) { },这样少了很多的麻烦

image.png

这个的版本控制 一定要注意,mac 和ios 的都是比较新的版本才适配,老的navigationView 已经放弃

吐槽

juejin 的md 太难用了,代码格式 不能直接复制粘贴。iOS 的NavigationStack 虽然多平台都可以用,但是macos 用的更多的是 NavigationSplitView 来进行 ui 的分布控制。

Kapture 2023-05-26 at 18.08.06.gif

遇到的坑

这个最大的坑就是 push 的时候 如果不是一个View 就全要从新考虑替换掉Link 的写法,这也是SwiftUI和UIKit 的思想不一样的原因,View的编写用SwiftUI 效率是很高,UIKit的navigation 放开了点击的事件,但是SwiftUI 想的是尽量不要在view 里面写方法关于逻辑的,这个事写SwiftUI的一个个人感觉

入口和出口对于SwiftUI 都是一个简单的变量,可以 @State 也可能是一个@Binding 变量。但是绝对不是一个Bool var + 一个刷新方法放在nav 里面