SwiftUI — Navigation

SwiftUI 中,NavigationStackNavigationViewNavigationSplitView 是用于实现导航功能的三种主要方式,它们的作用是帮助开发者实现分层次的视图结构(如页面导航)。这三者的区别主要体现在:引入的时间(历史变迁)适用场景功能表现

1. NavigationView #

NavigationViewSwiftUI 1.0(iOS 13)引入的最早导航容器组件,用于创建导航界面,例如带返回按钮的页面切换(类似 UINavigationController 的功能)。

特点 #

  • 用于包裹导航视图的容器。
  • 支持单列导航,适合简单的场景。
  • 逐步被替换:由于其局限性,在 iOS 16 中逐渐被 NavigationStackNavigationSplitView 取代。

用法示例 #

import SwiftUI

struct NavigationViewExample: View {
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(
                    destination: Text("Second View"),
                    label: {
                        Text("Go to Second View")
                    }
                )
            }
            .navigationTitle("First View")
        }
    }
}

优缺点 #

  • 优点:

  • 易于理解和使用,对于简单的页面导航非常方便。

  • 默认带有标题栏,可自动提供导航返回按钮、标题(navigationTitle)等。

  • 缺点:

  • 有限的控制能力:只适用于一对一导航,不支持复杂的导航行为。

  • 在多窗口场景下(如 iPad 分屏)不够灵活。

  • 不支持高效的导航路径管理(不像 NavigationStack 提供导航路径状态)。


2. NavigationStack #

NavigationStackiOS 16 引入的更现代的导航组件,旨在解决 NavigationView 的不足。它提供了更加强大的功能,例如路径(NavigationPath)的动态导航管理,为复杂导航场景提供了更多灵活性。

特点 #

  • 适合替代 NavigationView,用于管理深层嵌套导航结构。
  • 支持动态路径状态管理(NavigationPath),可以通过状态变量在任意地方新增/移除导航历史。
  • 多层级导航变得更加高效和直观,支持自定义返回跳转等操作。

用法示例 #

import SwiftUI

struct NavigationStackExample: View {
    @State private var path = NavigationPath() // 管理路径的状态

    var body: some View {
        NavigationStack(path: $path) {
            VStack {
                Button("Go to Details") {
                    path.append("DetailView") // 推入导航栈
                }
            }
            .navigationDestination(for: String.self) { value in
                if value == "DetailView" {
                    Text("This is the Detail View")
                }
            }
            .navigationTitle("Main View")
        }
    }
}

优缺点 #

  • 优点:

  • 层级导航管理强大: 支持动态路径(栈式浏览历史),可以灵活管理多级导航,适合复杂项目。

  • 更灵活状态管理: 可通过路径 (NavigationPath) 管控导航层级,支持程序化导航。

  • 更现代和推荐,逐渐成为导航的主力框架。

  • 缺点:

  • 仅支持从 iOS 16 开始,因此在向下兼容的项目中可能不适用。

  • NavigationView 实现复杂一些(需要路径管理思想)。


3. NavigationSplitView #

NavigationSplitViewiOS 16 引入的导航组件,专门用于实现 分栏分割导航(Split View),这在 iPad 和大型屏幕场景下尤其常见。例如经典的邮件客户端布局:左侧显示消息列表,右侧显示消息详情。

特点 #

  • 适用于 iPad、Mac 或支持多窗口的大屏设备,以及可选支持小屏设备(如 iPhone)。
  • 提供主页面、辅助页面、详细页面的划分。
  • 类似于 UIKit 中的 UISplitViewController,非常适合 多栏布局

用法示例 #

import SwiftUI

struct NavigationSplitViewExample: View {
    @State private var selection: String? = nil

    var body: some View {
        NavigationSplitView {
            List(["Item 1", "Item 2", "Item 3"], id: \.self, selection: $selection) { item in
                Text(item)
            }
        } detail: {
            if let selection = selection {
                Text("Detail of \(selection)")
            } else {
                Text("Please select an item.")
            }
        }
    }
}

优缺点 #

  • 优点:

  • 专为 分栏布局 设计,在大屏幕上(如 iPad 或 Mac)提供更好的用户体验。

  • 自带多栏分割的功能,无需手动分割视图,轻松实现类似邮件客户端的界面。

  • 自动适配小屏幕(iPhone 自动呈现单栏视图)。

  • 缺点:

  • 主要适合 多栏场景,对于单页面导航(如深层结构导航)可能不够简洁。

  • 需要熟悉多栏分割逻辑。


三者的对比总结 #

特性NavigationViewNavigationStackNavigationSplitView
引入版本iOS 13iOS 16iOS 16
适用场景简单导航(单一层级)复杂导航(多级嵌套和动态路径)分栏布局(大屏、邮件风格导航)
动态路径支持不支持支持不支持
多窗口适配较弱(不灵活)很强(多栏布局自动适配 iPad/iPhone)
多栏支持不支持不支持支持
推荐使用场景简单项目中大型项目,深层导航管理大屏项目(iPad、Mac)
向前兼容性iOS 13+iOS 16+iOS 16+

选择哪种方式? #

  • NavigationView:

  • 如果你的项目需要支持 iOS 13+ 用户

  • 如果导航需求较简单(例如没有多级动态导航)。

  • 如果是一个小型工程。

  • NavigationStack:

  • 如果你的项目目标是 iOS 16 或更高版本

  • 如果需要管理复杂的多级导航情况(例如电商应用,包含类别、商品、详情页等分级导航)。

  • 如果需要动态导航回溯(例如用户从路径 A 跳转到路径 B 时需要自定义逻辑)。

  • NavigationSplitView:

  • 如果你的应用运行在大屏(如 iPad 和 Mac)上,且需要多栏分割布局。

  • 如果想实现类似邮件客户端或消息应用那种分栏导航。

  • 如果你的界面关键内容分为 “主导航栏+详细内容区域” 的层级结构。


未来趋势 #

Apple 在 SwiftUI 的导航管理上,正在逐渐淘汰 NavigationView,并推荐开发者更多地使用 NavigationStackNavigationSplitView

  1. 对于中小型项目,NavigationStack 将为核心导航管理提供更强的灵活性和控制。
  2. 对于跨平台和大屏应用,NavigationSplitView 是未来设计多栏界面的主力方案。

如果你正在开发新项目,目标是 iOS 16 或更高版本,优先选择 NavigationStack NavigationSplitView,以便跟上技术更新的最佳实践。 😊

静态场景

动态,推荐尽量多用动态,灵活一些。

本文共 1898 字,上次修改于 Jan 5, 2025