I am trying to have a carousel in SwiftUI which automatically sliding to the next page. I implemented the solution below:
struct CarouselView: View {
let timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()
@State var selection = 0
let carouselViews: Array<WelcomeImageModel> =[....]
var body: some View {
VStack {
TabView(selection: $selection) {
ForEach(carouselViews) { view in
ZStack {
Image(view.image)
.resizable()
.aspectRatio(contentMode: .fill)
.ignoresSafeArea()
VStack {
Text(view.title)
Text(view.description)
}
}
}
}
.tabViewStyle(PageTabViewStyle())
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
.onReceive(timer, perform: { _ in
withAnimation{
selection = selection < 5 ? selection + 1 : 0
}
})
}
.ignoresSafeArea()
}
}
The WelcomeImageModel
is just a struct to better handle the data, and it's not relevent here but there is 5 elements in it.
It seems that the selection
is not updating properly. If I manually slide, it came back to 0 automatically. any idea why selection is not properly increasing.
Thanks
The tag
of your tabs probably doesn't match your selection
! Your tabs are automatically tagged with the id
s of your WelcomeImageModel
s, by the ForEach
, and not 0 to 5 as your selection
expects.
An easy solution is to change the ForEach
to:
ForEach(carouselViews.indices, id: \.self) { i in
// use carouselViews[i] in here...
}
This will tag each tab with the index of tab.
Alternatively, add a index
property in WelcomeImageModel
.
struct WelcomeImageModel: Identifiable {
let image: String
let title: String
let description: String
let index: Int // add this
// I'm not sure how you implemented id
}
Give the models the indices 0 to 4, in the order that they appear.
let carouselViews: [WelcomeImageModel] = [
.init(...., index: 0),
.init(...., index: 1),
.init(...., index: 2),
.init(...., index: 3),
.init(...., index: 4),
]
Then you can do:
ForEach(carouselViews) { view in
ZStack {
// ...
}.tag(view.index)
}