使用 iOS 18 上的自适应 TabView 标签栏

Tabview 是从 iOS13 开始被引入的 SwiftUI 组件,用于创建在多个子视图之间切换的视图。在 WWDC 2024 中,苹果对 TabView 的功能和使用方法进行了多项改进,在本文中,我们将了解新版本中的新功能及其改进之处。

Enhancing your app’s content with tab navigation | Apple Developer Documentation
Keep your app content front and center while providing quick access to navigation using the tab bar.

Tabview 核心改进

  • 编程控制
  • 自适应平台
  • 自定义标签栏顺序
  • 将标签进行分组

创建基本的 Tabview

从 iOS18 开始,TabView 引入了全新的标签栏创建语法

iOS 17 及更早版本:使用 .tabItem 和 .tag 修饰符

在 iOS 17 及之前的版本中,TabView 通过 .tabItem 修饰符来定义每个标签的图标和文字,并使用 .tag 为每个标签赋予唯一标识。

TabView {                 
    HomeView()
        .tabItem {
            Image(systemName: "house.fill")
            Text("今日")
        }
        .tag(1)
  
    CategoryView()
        .tabItem {
            Image(systemName: "calendar")
            Text("统计")
        }
        .tag(2)
  
    SearchView()
        .tabItem {
            Image(systemName: "lightbulb.circle.fill")
            Text("分析")
        }
        .tag(3)
}

iOS 18:推荐使用 Tab 构造器

从 iOS 18 开始,Tabview 推荐使用Tab 构造器来创建标签页。这种方式更加简洁,更加符合 SwiftUI 数据驱动的理念

首先定义一个 enum 来表示每个 Tab:

enum Tabs: Equatable, Hashable, Identifiable {
    case projects
    case recent

    var id: Self { self }
}

然后使用它:

struct ContentView: View {
    @State private var selectedTab: Tabs = .projects

    enum Tabs: Equatable, Hashable, Identifiable {
        case projects
        case recent

        var id: Self { self }
    }

    var body: some View {
        TabView(selection: $selectedTab) {
            Tab("项目", systemImage: "folder.fill", value: Tabs.projects) {
                ProjectsListView()
            }

            Tab("最近", systemImage: "doc.fill", value: Tabs.recent) {
                Text("最近 Page")
            }
        }
    }
}

兼容 iOS 17 及之前版本

如果你要兼容 iOS17 或以前的版本,可以通过条件语句 if #available 来选择使用哪种语法:

if #available(iOS 18.0, *) {
    TabView {
        Tab("今日", systemImage: "house.fill") {
            HomeView()
        }

        Tab("统计", systemImage: "calendar") {
            CategoryView()
        }

        Tab("分析", systemImage: "lightbulb.circle.fill") {
            SearchView()
        }
    }
} else {
    // Fallback on earlier versions
    TabView {
        HomeView()
            .tabItem {
                Image(systemName: "house.fill")
                Text("今日")
            }
            .tag(1)

        CategoryView()
            .tabItem {
                Image(systemName: "calendar")
                Text("统计")
            }
            .tag(2)

        SearchView()
            .tabItem {
                Image(systemName: "lightbulb.circle.fill")
                Text("分析")
            }
            .tag(3)
    }
}  

使用新的 sidebarAdaptable 样式

TabView(selection: $selectedTab) {
    // Tabs
    // ..
}
.tabViewStyle(.sidebarAdaptable)
Enhancing your app’s content with tab navigation | Apple Developer Documentation
Keep your app content front and center while providing quick access to navigation using the tab bar.

使用 .tabViewCustomization 自定义 Tabview 样式

Exploring Tab View Styles in SwiftUI
Explore the different styles a tab view can have in a SwiftUI app on iOS and iPadOS.

使用 TabSection 为标签分组

使用 .tabViewSidebarBottomBar 添加菜单栏

https://www.createwithswift.com/exploring-tab-view-styles-in-swiftui/