A Simplest TabView Sample
ContentView
struct ContentView: View {
var body: some View {
TabView {
ForEach(1..<4) { id in
TabItemView(id: id)
}
}
}
}
TabItemView
struct TabItemView: View {
@State var id:Int
var body: some View {
Text("Tab \(id)")
.tabItem {
Text(String(id))
}
}
}
Life Cycle of Tab Item View
TabItemView
struct TabItemView: View {
@State var id:Int
var body: some View {
Text("Tab \(id)")
.tabItem {
Text(String(id))
}
.onAppear(perform: {
print("I am tab \(id)")
})
.onDisappear {
print("Tab \(id) am quit!")
}
}
}
Runs.
I am tab 1
Tab 1 am quit!
I am tab 2
Tab 2 am quit!
I am tab 3
Tab 3 am quit!
I am tab 1
Is the tab item view just hidden or actually quit when you change a tab?
TabItemView
struct TabItemView: View {
@State var id:Int
@State private var title = ""
var body: some View {
HStack {
Text("Tab \(id)")
.onAppear(perform: {
print("I am tab \(id)")
})
.onDisappear {
print("Tab \(id) am quit!")
}
TextField("Title", text: $title)
}
.tabItem {
Text(String(id))
}
.padding()
}
}
Input "Test" in tab 1, and change to other tabs, then change back to tab 1. You will see the "Test" is still there. That means the tab item view was just hidden, not quit.
Change Tab Name
TabItemView
struct TabItemView: View {
@State var id:Int
@State private var title = ""
var body: some View {
HStack {
Text("Tab \(id)")
.onAppear(perform: {
print("I am tab \(id)")
})
.onDisappear {
print("Tab \(id) am quit!")
}
TextField("Title", text: $title)
}
.tabItem {
Text(getTabName())
}
.padding()
}
private func getTabName() -> String {
if title.isEmpty {
return String(id)
}
return title
}
}
Put Indicators in Window's Title Bar
ContentView
@main
struct TabView_SampleApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.windowToolbarStyle(.unifiedCompact(showsTitle: false))
}
}
The indicators worked. But the tab title no longer worked.
Fix Tab Title
TabItemView
struct TabItemView: View {
@Binding var tabContent:TabContent
var body: some View {
HStack {
Text("Tab \(tabContent.id)")
TextField("Title", text: $tabContent.title)
.frame(minWidth: 300)
}
.tabItem {
Text(getTabName())
}
.padding()
}
private func getTabName() -> String {
if tabContent.title.isEmpty {
return String(tabContent.id)
}
return tabContent.title
}
}
struct TabContent:Identifiable, Equatable, Hashable {
var id = 0
var title = ""
}
ContentView
struct ContentView: View {
@State private var tabContents:[TabContent] = {
(1..<4).map { TabContent(id: $0) }
}()
@State private var currentTabContent = TabContent(id: 1)
var body: some View {
ForEach($tabContents) { $tabContent in
if currentTabContent.id == tabContent.id {
TabItemView(tabContent: $tabContent)
}
}
.toolbar {
HStack {
Picker(String(currentTabContent.title), selection: $currentTabContent) {
ForEach(tabContents) { tabContent in
Text(tabContent.title.isEmpty ? String(tabContent.id) : tabContent.title).tag(tabContent)
}
}
.pickerStyle(.segmented)
.onChange(of: currentTabContent) { newValue in
if let index = tabContents.map({$0.id}).firstIndex(of: newValue.id) {
tabContents[index] = newValue
}
}
Spacer()
}
}
.frame(width: 400, height: 50)
}
}