TabView 在选项卡上保持状态更改 SwiftUI
TabView keeping state on tab changes SwiftUI
当我的 TabView
选项卡更改时,我正在重新加载 View
。我试图在初始数据加载时从 API 获取数据时显示 ProgressView
,但每次更改选项卡时都会重新加载它,即使在导航到另一个视图之后也是如此。如果我删除我的 ProgressView
它可以工作,它只是在加载数据时看起来不太好。
我原以为这会是一项简单的任务,但我还没有找到很好的解决方案。我找到了 StatefulTabView 但它似乎在 iOS 15 上坏了。我不确定我是否只是用我的视图模型做了一些不正确的事情。任何帮助将不胜感激。
查看模型
class RickAndMortyViewModel: ObservableObject {
private var cancellables = Set<AnyCancellable>()
@Published var dataone = RickandMorty(results: [])
@Published var datatwo = RickandMorty(results: [])
@Published var loadingone: Bool = false
@Published var loadingtwo: Bool = false
func getpageone() {
self.loadingone = true
URLSession.shared.dataTaskPublisher(for:URLRequest(url: URL(string: "https://rickandmortyapi.com/api/character/?page=1")!))
.map{ [=10=].data }
.decode(type: RickandMorty.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { results in
switch results {
case .finished:
self.loadingone = false
case .failure(let error):
print(error)
}
},receiveValue: { data in
self.dataone = data
})
.store(in: &cancellables)
}
func getpagetwo() {
self.loadingtwo = true
URLSession.shared.dataTaskPublisher(for:URLRequest(url: URL(string: "https://rickandmortyapi.com/api/character/?page=2")!))
.map{ [=10=].data }
.decode(type: RickandMorty.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { results in
switch results {
case .finished:
self.loadingtwo = false
case .failure(let error):
print(error)
}
},receiveValue: { data in
self.datatwo = data
})
.store(in: &cancellables)
}
}
查看
struct ContentView: View {
@StateObject var viewmodel = RickAndMortyViewModel()
var body: some View {
TabView {
NavigationView {
if viewmodel.loadingone {
ProgressView("Loading Page 1")
.navigationTitle("Page 1")
} else {
List {
ForEach(viewmodel.dataone.results, id: \.id) { character in
NavigationLink(destination: EmptyView()) {
Text(character.name)
}
}
}
.navigationTitle("Page 1")
}
}
.onAppear {
viewmodel.getpageone()
}
.tabItem {
Label("Page 1", systemImage: "person")
}
.tag(1)
NavigationView {
if viewmodel.loadingtwo {
ProgressView("Loading Page 2")
.navigationTitle("Page 2")
} else {
List {
ForEach(viewmodel.datatwo.results, id: \.id) { character in
NavigationLink(destination: EmptyView()) {
Text(character.name)
}
}
}
.navigationTitle("Page 2")
}
}
.onAppear {
viewmodel.getpagetwo()
}
.tabItem {
Label("Page 2", systemImage: "person")
}
.tag(2)
}
}
}
将它们分解为具有独立@StateObject 的视图,除非您想在它们之间共享数据
class RickAndMortyViewModel: ObservableObject {
private var cancellables = Set<AnyCancellable>()
@Published var dataone = RickandMorty(results: [])
@Published var datatwo = RickandMorty(results: [])
@Published var loadingone: Bool = false
@Published var loadingtwo: Bool = false
func getpageone() {
self.loadingone = true
URLSession.shared.dataTaskPublisher(for:URLRequest(url: URL(string: "https://rickandmortyapi.com/api/character/?page=1")!))
.map{ [=10=].data }
.decode(type: RickandMorty.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { results in
switch results {
case .finished:
self.loadingone = false
case .failure(let error):
print(error)
}
},receiveValue: { data in
self.dataone = data
})
.store(in: &cancellables)
}
func getpagetwo() {
self.loadingtwo = true
URLSession.shared.dataTaskPublisher(for:URLRequest(url: URL(string: "https://rickandmortyapi.com/api/character/?page=2")!))
.map{ [=10=].data }
.decode(type: RickandMorty.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { results in
switch results {
case .finished:
self.loadingtwo = false
case .failure(let error):
print(error)
}
},receiveValue: { data in
self.datatwo = data
})
.store(in: &cancellables)
}
}
struct ContentView: View {
@StateObject var viewmodel = RickAndMortyViewModel()
var body: some View {
TabView {
TabPageOne()
.tabItem {
Label("Page 1", systemImage: "person")
}
.tag(1)
TabPageTwo()
.tabItem {
Label("Page 2", systemImage: "person")
}
.tag(2)
}
}
}
struct TabPageOne: View {
@StateObject var viewmodel = RickAndMortyViewModel()
var body: some View {
NavigationView {
if viewmodel.loadingone {
ProgressView("Loading Page 1")
.navigationTitle("Page 1")
} else {
List {
ForEach(viewmodel.dataone.results, id: \.id) { character in
NavigationLink(destination: EmptyView()) {
Text(character.name)
}
}
}
.navigationTitle("Page 1")
}
}
.onAppear {
viewmodel.getpageone()
}
}
}
struct TabPageTwo: View {
@StateObject var viewmodel = RickAndMortyViewModel()
var body: some View {
NavigationView {
if viewmodel.loadingtwo {
ProgressView("Loading Page 2")
.navigationTitle("Page 2")
} else {
List {
ForEach(viewmodel.datatwo.results, id: \.id) { character in
NavigationLink(destination: EmptyView()) {
Text(character.name)
}
}
}
.navigationTitle("Page 2")
}
}
.onAppear {
viewmodel.getpagetwo()
}
}
}
我明白你的意思了(我想)。
我的网速很快,所以我看不到 ProgressView
的进展。
你可以试试这个in RickAndMortyViewModel
:
@Published var loadingone: Bool = true
@Published var loadingtwo: Bool = true
func getpageone() {
if !loadingone {return}
...
}
func getpagetwo() {
if !loadingtwo {return}
...
}
当我的 TabView
选项卡更改时,我正在重新加载 View
。我试图在初始数据加载时从 API 获取数据时显示 ProgressView
,但每次更改选项卡时都会重新加载它,即使在导航到另一个视图之后也是如此。如果我删除我的 ProgressView
它可以工作,它只是在加载数据时看起来不太好。
我原以为这会是一项简单的任务,但我还没有找到很好的解决方案。我找到了 StatefulTabView 但它似乎在 iOS 15 上坏了。我不确定我是否只是用我的视图模型做了一些不正确的事情。任何帮助将不胜感激。
查看模型
class RickAndMortyViewModel: ObservableObject {
private var cancellables = Set<AnyCancellable>()
@Published var dataone = RickandMorty(results: [])
@Published var datatwo = RickandMorty(results: [])
@Published var loadingone: Bool = false
@Published var loadingtwo: Bool = false
func getpageone() {
self.loadingone = true
URLSession.shared.dataTaskPublisher(for:URLRequest(url: URL(string: "https://rickandmortyapi.com/api/character/?page=1")!))
.map{ [=10=].data }
.decode(type: RickandMorty.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { results in
switch results {
case .finished:
self.loadingone = false
case .failure(let error):
print(error)
}
},receiveValue: { data in
self.dataone = data
})
.store(in: &cancellables)
}
func getpagetwo() {
self.loadingtwo = true
URLSession.shared.dataTaskPublisher(for:URLRequest(url: URL(string: "https://rickandmortyapi.com/api/character/?page=2")!))
.map{ [=10=].data }
.decode(type: RickandMorty.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { results in
switch results {
case .finished:
self.loadingtwo = false
case .failure(let error):
print(error)
}
},receiveValue: { data in
self.datatwo = data
})
.store(in: &cancellables)
}
}
查看
struct ContentView: View {
@StateObject var viewmodel = RickAndMortyViewModel()
var body: some View {
TabView {
NavigationView {
if viewmodel.loadingone {
ProgressView("Loading Page 1")
.navigationTitle("Page 1")
} else {
List {
ForEach(viewmodel.dataone.results, id: \.id) { character in
NavigationLink(destination: EmptyView()) {
Text(character.name)
}
}
}
.navigationTitle("Page 1")
}
}
.onAppear {
viewmodel.getpageone()
}
.tabItem {
Label("Page 1", systemImage: "person")
}
.tag(1)
NavigationView {
if viewmodel.loadingtwo {
ProgressView("Loading Page 2")
.navigationTitle("Page 2")
} else {
List {
ForEach(viewmodel.datatwo.results, id: \.id) { character in
NavigationLink(destination: EmptyView()) {
Text(character.name)
}
}
}
.navigationTitle("Page 2")
}
}
.onAppear {
viewmodel.getpagetwo()
}
.tabItem {
Label("Page 2", systemImage: "person")
}
.tag(2)
}
}
}
将它们分解为具有独立@StateObject 的视图,除非您想在它们之间共享数据
class RickAndMortyViewModel: ObservableObject {
private var cancellables = Set<AnyCancellable>()
@Published var dataone = RickandMorty(results: [])
@Published var datatwo = RickandMorty(results: [])
@Published var loadingone: Bool = false
@Published var loadingtwo: Bool = false
func getpageone() {
self.loadingone = true
URLSession.shared.dataTaskPublisher(for:URLRequest(url: URL(string: "https://rickandmortyapi.com/api/character/?page=1")!))
.map{ [=10=].data }
.decode(type: RickandMorty.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { results in
switch results {
case .finished:
self.loadingone = false
case .failure(let error):
print(error)
}
},receiveValue: { data in
self.dataone = data
})
.store(in: &cancellables)
}
func getpagetwo() {
self.loadingtwo = true
URLSession.shared.dataTaskPublisher(for:URLRequest(url: URL(string: "https://rickandmortyapi.com/api/character/?page=2")!))
.map{ [=10=].data }
.decode(type: RickandMorty.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { results in
switch results {
case .finished:
self.loadingtwo = false
case .failure(let error):
print(error)
}
},receiveValue: { data in
self.datatwo = data
})
.store(in: &cancellables)
}
}
struct ContentView: View {
@StateObject var viewmodel = RickAndMortyViewModel()
var body: some View {
TabView {
TabPageOne()
.tabItem {
Label("Page 1", systemImage: "person")
}
.tag(1)
TabPageTwo()
.tabItem {
Label("Page 2", systemImage: "person")
}
.tag(2)
}
}
}
struct TabPageOne: View {
@StateObject var viewmodel = RickAndMortyViewModel()
var body: some View {
NavigationView {
if viewmodel.loadingone {
ProgressView("Loading Page 1")
.navigationTitle("Page 1")
} else {
List {
ForEach(viewmodel.dataone.results, id: \.id) { character in
NavigationLink(destination: EmptyView()) {
Text(character.name)
}
}
}
.navigationTitle("Page 1")
}
}
.onAppear {
viewmodel.getpageone()
}
}
}
struct TabPageTwo: View {
@StateObject var viewmodel = RickAndMortyViewModel()
var body: some View {
NavigationView {
if viewmodel.loadingtwo {
ProgressView("Loading Page 2")
.navigationTitle("Page 2")
} else {
List {
ForEach(viewmodel.datatwo.results, id: \.id) { character in
NavigationLink(destination: EmptyView()) {
Text(character.name)
}
}
}
.navigationTitle("Page 2")
}
}
.onAppear {
viewmodel.getpagetwo()
}
}
}
我明白你的意思了(我想)。
我的网速很快,所以我看不到 ProgressView
的进展。
你可以试试这个in RickAndMortyViewModel
:
@Published var loadingone: Bool = true
@Published var loadingtwo: Bool = true
func getpageone() {
if !loadingone {return}
...
}
func getpagetwo() {
if !loadingtwo {return}
...
}