在现今最流行的 App中,例如 Facebook、Instagram 和 Twitter,你不难发现它们都使用标签介面。 这种介面在App底部会出现一个标签栏,让使用者可以在不同功能之间快速切换。 如使用 UIKit ,您可以利用UITabBarController
来建立标签栏界面。 SwiftUI 框架则提供了一个名为TabView
的 UI 组件,供开发者在App制作标签介面。
在本章中,我们将向你解构 TabView
并建立标签栏界面、处理标签选择以及自订标签栏的外观。
假设您已经使用 Xcode 开启了一个 SwiftUI 项目,让我们从一个简单的Text
视图开始,如下所示:
struct ContentView: View {
var body: some View {
Text("Home Tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
}
}
要将这个文字视图嵌入到标签栏中,你只需要利用 TabView
组件包装它就可以。而通过附加 .tabItem
修饰器,你就可以设置标签项的描述,如下所示:
struct ContentView: View {
var body: some View {
TabView {
Text("Home Tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
.tabItem {
Image(systemName: "house.fill")
Text("Home")
}
}
}
}
这就建立了一个带有选项的标签列。 在示例代码中,选项同时具有图像和文字,但您可以随意删除其中之一。
要显示更多选项,您只需在 TabView
中添加子视图,如下所示:
TabView {
Text("Home Tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
.tabItem {
Image(systemName: "house.fill")
Text("Home")
}
Text("Bookmark Tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
.tabItem {
Image(systemName: "bookmark.circle.fill")
Text("Bookmark")
}
Text("Video Tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
.tabItem {
Image(systemName: "video.circle.fill")
Text("Video")
}
Text("Profile Tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
.tabItem {
Image(systemName: "person.crop.circle")
Text("Profile")
}
}
这就建立了一个带有 4 个选项的标签列。
在默认的情况下,标签列项目的颜色是设置为蓝色。 您可以通过将 .accentColor
修饰器附加到 TabView
来修改其颜色,如下所示:
TabView {
}
.accentColor(.red)
如果您将以上代码加到TabView
,标签列的颜色就会修改为白色。
标签视图会自动处理使用者的选择,当使用者点击其中一个项目标签视图就会切换至相关项目视图。 在某些情况,您可能希望以写程序方式切换到特定选项。 TabView
有另一个用于此目的的 init
方法。 该方法需要一个包含选项卡标签值的状态变量:
TabView(selection: $selection)
举例,在 ContentView 中声明以下状态变量:
@State private var selection = 0
这里我们将 selection
变量的原始值设定为0
,这是第一个选项的标签值。 我们还没有为每个选项定义标签值。 因此,像这样修改代码并为每个选项附加 tag
修饰器:
TabView(selection: $selection) {
Text("Home Tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
.tabItem {
Image(systemName: "house.fill")
Text("Home")
}
.tag(0)
Text("Bookmark Tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
.tabItem {
Image(systemName: "bookmark.circle.fill")
Text("Bookmark")
}
.tag(1)
Text("Video Tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
.tabItem {
Image(systemName: "video.circle.fill")
Text("Video")
}
.tag(2)
Text("Profile Tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
.tabItem {
Image(systemName: "person.crop.circle")
Text("Profile")
}
.tag(3)
}
我们通过附加 tag
修饰器为每个选项提供唯一索引。 TabView
也绑定到 selection
值。 要以编程方式切换到指定选项,就只需要修改 selection
变量的值。
您可以建立一个 Next 按钮来切换至下一个选项,如下所示:
ZStack(alignment: .topTrailing) {
TabView(selection: $selection) {
.
.
.
}
.accentColor(.red)
Button {
selection = (selection + 1) % 4
} label: {
Text("Next")
.font(.system(.headline, design: .rounded))
.padding()
.foregroundColor(.white)
.background(Color.red)
.cornerRadius(10.0)
.padding()
}
}
进行修改后,在预览中运行App,您可以点击 Next 按钮跳至不同选项。
你可以通过以下代码利用 NavigationStack
包裹 TabView
组件将标签视图嵌入导航视图中:
NavigationStack {
TabView(selection: $selection) {
.
.
.
}
.navigationTitle("TabView Demo")
}
在 UIKit 中,还有一个名为 hidesBottomBarWhenPushed
的选项,它允许您在使用导航界时自动隐藏标签栏。 SwiftUI 也内置了此功能。 您可以像这样修改代码:
NavigationStack {
TabView(selection: $selection) {
List(1...10, id: \.self) { index in
NavigationLink(
destination: Text("Item #\(index) Details"),
label: {
Text("Item #\(index)")
.font(.system(size: 20, weight: .bold, design: .rounded))
})
}
.listStyle(.plain)
.tabItem {
Image(systemName: "house.fill")
Text("Home")
}
.tag(0)
Text("Bookmark Tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
.tabItem {
Image(systemName: "bookmark.circle.fill")
Text("Bookmark")
}
.tag(1)
Text("Video Tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
.tabItem {
Image(systemName: "video.circle.fill")
Text("Video")
}
.tag(2)
Text("Profile Tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
.tabItem {
Image(systemName: "person.crop.circle")
Text("Profile")
}
.tag(3)
}
.accentColor(.red)
.navigationTitle("TabView Demo")
}
我们只是修改了 Home 选项卡的代码以显示项目列表。 我们用NavigationLink
包装每个列表项目,以便在选择该项时导航至详细信息视图。 如果您使用模拟器或在预览中运行App,当导航到详细信息视图时,标签栏就会自动隐藏。
就某些情况,您可能不希望隐藏选标签栏。 如果是这个样的话,您可以反过来建立导航界面。 不是将标签视图包装在导航视图中,而是将导航视图嵌入到标签视图中,如下所示:
TabView(selection: $selection) {
NavigationStack {
List(1...10, id: \.self) { index in
NavigationLink(
destination: Text("Item #\(index) Details"),
label: {
Text("Item #\(index)")
.font(.system(size: 20, weight: .bold, design: .rounded))
})
}
.navigationTitle("TabView Demo")
}
.tabItem {
Image(systemName: "house.fill")
Text("Home")
}
.tag(0)
.
.
.
}
现在,当您导航到项目的详细信息视图时,标签栏仍然存在。
在本章中,我们向您介绍了 TabView
的基础知识,它是 SwiftUI 中用于建立标签介面的 UI 组件。 SwiftUI框架没有为您提供许多用于自订标签栏的选项。 但是,您仍然可依赖 UIKit 的 API 来自订其外观。
在本章所准备的示例档中,有最后完整的 Xcode 项目,可供你下载参考:
https://www.appcoda.com/resources/swiftui4/SwiftUITabView.zip