I'm using TabView
to show pages of image:
TabView(selection: self.$index) {
ForEach(0..<100) { index in
PageImage(id: pageIds[index]).tag(index)
}
}
.tabViewStyle(.page(indexDisplayMode: .never))
Those images are asyncornized loaded from web and I have PageImage
like this:
@StateObject private var pageModel = PageImageModel()
...
var body: some View {
if let imageData = pageModel.imageData {
Image(uiImage: UIImage(data: imageData)!)
} else {
ProgressView(value: pageModel.progress)
.onAppear {
imageModel.load(id: id)
}
}
}
It works except the image only load after I reached that page. Is there anyway I could tell the TabView to preload pages (i.e. trigger the imageModel.load(id: id)
) before I reach that page? Thanks.
Edit: Something a bit unrelated. Currently, if your page view use if else
to return different view, then TabView will call body to render ALL pages when it is shown. My workaround is to wrap if else
in a ZStack
, now TabView will only render the page that is on screen.
It is already call next page to appear when you swipe. So only the second page of TabView won't be loaded because you haven't perform any swipe yet
There're many solution to overcome this, like put an onAppear
on TabView to load second page, or handle it properly in your PageImageModel
Incase you want to switch your page index without swipe gesture (buttons, events, ...), there're some solutions as well
PageImageModel
to handle it properlyHere's minimize sample code for your case that can be run on preview
struct PageView: View {
@Binding var data: [Int:String]
@Binding var currentIndex: Int
var id: Int
var body: some View {
if let value = data[id] {
Text(value).onAppear {
if id == currentIndex {
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
data[id+1] = "\(id+1)"
}
}
}
} else{
ProgressView().onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
data[id] = "\(id)"
}
}
}
}
}
struct TestNextTabView: View {
@State var data: [Int:String] = [:]
@State var next = 0
@State var index = 0
var body: some View {
VStack {
Text("preload: \(next)")
TabView(selection: $index) {
ForEach(0..<100) { i in
PageView(data: $data, currentIndex: $index, id: i)
}
}
.tabViewStyle(.page(indexDisplayMode: .never))
Button("next") { index += 1 }
}
}
}
struct TestOtherTestViews_Previews: PreviewProvider {
static var previews: some View {
TestNextTabView()
}
}