SwiftUI TabView 解析
TabView
是 SwiftUI 中用于创建标签页视图的组件,类似于 UIKit 中的 UITabBarController
。下面我将解释源代码并提供使用示例。
源代码解析
基本结构
swift
public struct TabView<SelectionValue, Content> : View
where SelectionValue : Hashable, Content : View
TabView
是一个泛型结构体,遵循View
协议SelectionValue
是用于跟踪当前选中标签的值的类型,必须遵循Hashable
协议Content
是视图内容的类型,必须遵循View
协议
初始化方法
- 旧版初始化方法 (已弃用)
swift
@available(iOS, deprecated: 100000.0, message: "Use TabContentBuilder-based TabView initializers instead")
public init(selection: Binding<SelectionValue>?, @ViewBuilder content: () -> Content)
- 这个初始化方法已被标记为弃用
- 使用
@ViewBuilder
构建内容 - 接受一个可选的
Binding<SelectionValue>
用于跟踪当前选中的标签
使用示例
swift
import SwiftUI
struct OldTabViewExample: View {
@State private var selectedTab: Int = 0
var body: some View {
TabView(selection: $selectedTab) { // selection 是可选 Binding
HomeView()
.tabItem { Label("首页", systemImage: "house.fill") }
.tag(0)
CalendarView()
.tabItem { Label("日历", systemImage: "calendar") }
.tag(1)
SettingsView()
.tabItem { Label("设置", systemImage: "gearshape") }
.tag(2)
}
}
}
- 新版初始化方法 (iOS 18+)
swift
@available(iOS 18.0, macOS 15.0, tvOS 18.0, watchOS 11.0, visionOS 2.0, *)
public init<C>(selection: Binding<SelectionValue>, @TabContentBuilder<SelectionValue> content: () -> C)
where Content == TabContentBuilder<SelectionValue>.Content<C>, C : TabContent
- 使用新的
@TabContentBuilder
构建内容 - 需要 iOS 18+ 等新系统版本
- 提供更好的类型安全性和更简洁的语法
使用示例
swift
import SwiftUI
struct NewTabViewExample: View {
@State private var selectedTab: Int = 0
var body: some View {
if #available(iOS 18.0, *) {
TabView(selection: $selectedTab) { // 必须有 Binding
Tab(value: 0) {
HomeView()
}
.tabItem { Label("首页", systemImage: "house.fill") }
Tab(value: 1) {
CalendarView()
}
.tabItem { Label("日历", systemImage: "calendar") }
Tab(value: 2) {
SettingsView()
}
.tabItem { Label("设置", systemImage: "gearshape") }
}
} else {
Text("请升级到 iOS 18 使用该写法")
}
}
}
扩展方法
- 当 SelectionValue 为 Int 时的简化初始化
swift
extension TabView where SelectionValue == Int {
nonisolated public init(@ViewBuilder content: () -> Content)
}
- 当标签选择值是 Int 类型时,可以省略 selection 参数
这也就是最常见的使用方法了
示例
swift
import SwiftUI
struct IntTabViewExample: View {
var body: some View {
TabView { // 没有 selection
HomeView()
.tabItem { Label("首页", systemImage: "house.fill") }
.tag(0)
CalendarView()
.tabItem { Label("日历", systemImage: "calendar") }
.tag(1)
SettingsView()
.tabItem { Label("设置", systemImage: "gearshape") }
.tag(2)
}
}
}
- 当 SelectionValue 为 Never 时的初始化 (iOS 18+)
swift
extension TabView {
public init<C>(@TabContentBuilder<Never> content: () -> C)
where SelectionValue == Never, Content == TabContentBuilder<Never>.Content<C>, C : TabContent
}
- 用于不需要选择功能的标签视图
- 需要 iOS 18+ 等新系统版本
示例
swift
struct StaticTabView: View {
var body: some View {
TabView {
Tab("Home") {
Text("Home Content")
}
Tab("About") {
Text("About Content")
}
}
}
}
更多的使用示例
基础示例 (iOS 13+ 兼容)
swift
struct BasicTabView: View {
@State private var selectedTab = 0
var body: some View {
TabView(selection: $selectedTab) {
Text("First Tab")
.tabItem {
Image(systemName: "1.square.fill")
Text("First")
}
.tag(0)
Text("Second Tab")
.tabItem {
Image(systemName: "2.square.fill")
Text("Second")
}
.tag(1)
}
}
}
简化版 (当 SelectionValue 是 Int)
swift
struct SimpleTabView: View {
var body: some View {
TabView {
Text("Home")
.tabItem {
Label("Home", systemImage: "house")
}
Text("Settings")
.tabItem {
Label("Settings", systemImage: "gear")
}
}
}
}
iOS 18+ 新 API 示例
swift
@available(iOS 18.0, macOS 15.0, *)
struct NewTabViewExample: View {
@State private var selectedTab: String = "home"
var body: some View {
TabView(selection: $selectedTab) {
Tab("Home", value: "home") {
Text("Home Content")
}
Tab("Profile", value: "profile") {
Text("Profile Content")
}
Tab("Settings", value: "settings") {
Text("Settings Content")
}
}
}
}
不需要选择功能的标签视图 (iOS 18+)
swift
@available(iOS 18.0, macOS 15.0, *)
struct StaticTabView: View {
var body: some View {
TabView {
Tab("Home") {
Text("Home Content")
}
Tab("About") {
Text("About Content")
}
}
}
}
tabItem
另外tabItem的作用是布局一个视图作为标签页元素,所有可以向其中加入视图,包括允许你指定每个标签页在标签栏中显示的图标和标题。
tabItem 闭包中,你通常会提供一个 Label、Image 或 Text 视图,或者它们的组合。
主要特性
- 必须与 TabView 一起使用:tabItem 只能应用于 TabView 的子视图
- 需要配合 tag 修饰符使用:如果你需要跟踪当前选中的标签
- 自动适应外观:系统会根据当前环境自动调整标签项的外观
高级用法,动态改变标签项
swift
.tabItem {
Label(showDetails ? "Detailed" : "Simple",
systemImage: showDetails ? "info.circle.fill" : "info.circle")
}
总结
TabView
是 SwiftUI 中创建标签页界面的主要组件- 旧版 API 使用
tabItem
和tag
修饰符定义标签 - iOS 18+ 引入了新的
Tab
视图和@TabContentBuilder
,提供了更简洁的语法 - 根据是否需要跟踪当前选中的标签,可以选择不同的初始化方法
- 当选择值是 Int 类型时,可以使用简化版的初始化方法
新的 iOS 18 API 提供了更直观的方式来定义标签视图,但如果你需要支持旧版系统,仍然需要使用传统的 tabItem
方法。
本文使用 「Markdown 在线编辑器 | 公众号内容排版工具」 排版