如何在 SwiftUI 中使用 TabbedView?
Posted
技术标签:
【中文标题】如何在 SwiftUI 中使用 TabbedView?【英文标题】:How do I use TabbedView in SwiftUI? 【发布时间】:2019-11-06 22:38:01 【问题描述】:struct ContentView : View
var body: some View
NavigationView
TabbedView
PasswordGenerator()
.tabItemLabel
Image("KeyGlyph")
Text("Generator")
PasswordGeneratorSettings()
.tabItemLabel
Image("SettingsGlyph")
Text("Settings")
这不会编译,但它已在 WWDC 的 Swift Essentials 视频中使用(见第 54:30 分钟),我已经看到了一些解决方法,例如 VStack 解决方法(但即使这样也有很多缺陷,左侧选项卡也是最左边和右边的选项卡离右边太远,切换选项卡时只有最初加载的第一个选项卡和另一个选项卡保持空白并且使用标签没有帮助)。那么如何有两个选项卡来加载视图并具有图像和文本?
【问题讨论】:
你有 macOS Catalina 吗? @Lu_ 是的,我有 macOS Catalina。 【参考方案1】:TabbedView()
已被弃用,请改用TabView()
。
从我使用 UIButton 和 UIView 的 tag()
开始,使用整数选择视图对我来说很糟糕,最好列举你正在做的事情,而不是分配一个范围非常大的硬编码值。即Int.min()
到Int.max()
。这也使代码在将来更易于阅读和维护。
TabView(selection: )
可用于选择索引,声明为:
public struct TabView<SelectionValue, Content> : View where SelectionValue : Hashable, Content : View
public init(selection: Binding<SelectionValue>?, @ViewBuilder content: () -> Content)
…
这意味着您可以选择具有任何可散列内容的索引。
我们可以使用符合Hashable
的enum
来包含选项卡列表,
这样以后可以使用一个 Observable 来帮助控制和加载视图的状态。或者将枚举作为应用程序状态的一部分。我相信您可以使用大量资源来找到满足您需求的适当解决方案。
struct MainTabView: View
@State private var selection: Tabs = .profile
private enum Tabs: Hashable
case content
case profile
var body: some View
TabView(selection: $selection)
// Learn Content
Text("The First Tab")
.tabItem
Image(systemName: "book")
Text("Learn")
.tag(Tabs.content)
// The Users Profile View.
ProfileView()
.tabItem
Image(systemName: "person.circle")
Text("Profile")
.tag(Tabs.profile)
【讨论】:
【参考方案2】:TabbedView 已弃用并已重命名为 TabView 你可以像这样使用 TabView
TabView
(Text("Tab 1!").tabItem
Text("First")
)
(Text("Tab 2!").tabItem
Text("Second")
)
【讨论】:
【参考方案3】:对于那些仍在寻找如何做到这一点的人,这里是 Xcode 11 GM 的更新。
struct Tabs: View
@State private var selected = 0
var body: some View
TabView(selection: $selected)
MyFirstView()
.tabItem
Image(systemName: (selected == 0 ? "star.fill" : "star"))
Text("One")
.tag(0)
MySecondView()
.tabItem
Image(systemName: (selected == 1 ? "star.fill" : "star"))
Text("Two")
.tag(1)
MyThirdView()
.tabItem
Image(systemName: (selected == 2 ? "star.fill" : "star"))
Text("Three")
.tag(2)
.edgesIgnoringSafeArea(.all) // Important if you want NavigationViews to go under the status bar...
【讨论】:
嘿,我在使用 TabView 和导航视图时遇到了确切的问题。但是,如果我设置 .edgesIgnoringSafeArea(.all),我会将所有内容扩展到屏幕之外。我该如何解决? 试试 edgesIgnoringSafeArea([.top, .bottom]) 或者你可能只想要 .top(取决于你的视图)【参考方案4】:从 Xcode 11 GM 开始,此代码有效:(来自 https://developer.apple.com/documentation/swiftui/tabview)
TabView
Text("The First Tab")
.tabItem
Image(systemName: "1.square.fill")
Text("First")
Text("Another Tab")
.tabItem
Image(systemName: "2.square.fill")
Text("Second")
Text("The Last Tab")
.tabItem
Image(systemName: "3.square.fill")
Text("Third")
.font(.headline)
【讨论】:
【参考方案5】:TabbedView 已弃用。
你现在可以改用TabView
struct AppTabbedView: View
@State private var selection = 3
var body: some View
TabView (selection:$selection)
Text("The First Tab")
.tabItem
Image(systemName: "1.square.fill")
Text("First")
.tag(1)
Text("Another Tab")
.tabItem
Image(systemName: "2.square.fill")
Text("Second")
.tag(2)
Text("The Last Tab")
.tabItem
Image(systemName: "3.square.fill")
Text("Third")
.tag(3)
.font(.headline)
【讨论】:
【参考方案6】:对于 XCode beta 3,以下内容应该可以工作:
import SwiftUI
struct Home : View
@State private var currentTab = 1
var body: some View
TabbedView(selection: $currentTab)
FirstView()
.tabItem
VStack
Image(systemName: "1.circle")
Text("First Tab")
.tag(1)
SecondView()
.tabItem
VStack
Image(systemName: "2.circle")
Text("Second Tab")
.tag(2)
不过,将标签标签包含在 VStack
中似乎是可选的。所以,你可能决定放弃这个,比如:
import SwiftUI
struct Home : View
@State private var currentTab = 1
var body: some View
TabbedView(selection: $currentTab)
FirstView()
.tabItem
Image(systemName: "1.circle")
Text("First Tab")
.tag(1)
SecondView()
.tabItem
Image(systemName: "2.circle")
Text("Second Tab")
.tag(2)
【讨论】:
如果我有一个只有图像的标签项,我该如何更改它的位置或对齐方式?【参考方案7】:您的代码应该可以工作,但这是一个已知问题,来自ios & iPadOS 13 Beta 2 Release Notes:
tabItemLabel(_:) 修饰符不接受 @ViewBuilder 闭包。
在解决此问题之前,唯一的解决方法是使用您提到的 VStack。
MyView()
.tabItemLabel(VStack
Image("resourceName")
Text("Item")
)
更新:
Xcode 11 beta 3 已修复此问题:
tabItemLabel(:) 修饰符 - 现在命名为 tabItem(:) - 现在接受 @ViewBuilder 闭包。
例子:
.tabItem
Image(systemName: "circle")
Text("Tab1")
【讨论】:
【参考方案8】:“TabbedView”的使用方式类似于以下:
struct TabView : View
@State private var selection = 1
var body: some View
TabbedView (selection: $selection)
InboxList()
.tabItemLabel(selection == 1 ? Image("second") : Image("first"))
.tag(1)
PostsList()
.tabItemLabel(Image("first"))
.tag(2)
Something()
.tabItemLabel(Image("first"))
.tag(3)
我不确定为什么您的示例无法编译,但您错过了每个“选项卡”上的 selection
参数和 .tag
属性。
顺便说一句,在当前 XCode 版本(beta 2)中,您不能同时将文本和图像显示为标签。
【讨论】:
以上是关于如何在 SwiftUI 中使用 TabbedView?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 SwiftUI 中使用 SFSafariViewController?
如何在 SwiftUI 中使用 .fileimporter 保存音频文件并检索文件并在 SwiftUI 列表中显示它们的文件名?