Using Swift5.3.2, iOS14.4.2, XCode12.4,
I am struggling with this new iOS14 feature for creating PageViews in SwiftUI.
It all works, except I cannot detect the moments of swipe !
I tried using .onChange(selectionIndex)
but as soon as I create this change-listener to the TabView's selectionIndex
, the swipe stalls. It is no longer smooth.
struct MyView: View {
@State var selectionIndex = 0
var body: some View {
TabView(selection: $selectionIndex) {
ForEach(mediaList.paths.indices, id: \.self) { index in
SomePageView(media: mediaList.paths[index])
}
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
.onChange(of: selectionIndex) { newIdx in
customDotsService.selectedIndex = newIdx // because TabView's PageViewStyle does not have little dots that can be placed somewhere else on screen...
sendCommand(index: newIdx) // some background task to send commands to other services...
}
}
}
Even if my onChange(selectionIndex) { newIdx in ... }
remains completely empty, the swipe stalls and memory goes to the loops.
It is really an annoying problem and I am on it since 4 days non-stop.
Any help highly appreciated.
What I need from Apple: a working PageView that has correct life-cycle methods .onAppear()
, .onChange(selectionIndex)
and its little-Dots-Indicator that can be placed anywhere on screen. Help universe, help that we get this in SwiftUI.
I implemented this solution and it works as expected. Need to add tag value to View
which is used in ForEach
, then call onChange
block and you'll able to detect swiping there.
struct OnboardingPagerView: View {
@ObservedObject private var viewModel = OnboardingPagerViewModel()
@State private var selectedPageIndex = 0
var body: some View {
VStack {
TabView(selection: $selectedPageIndex) {
ForEach(viewModel.items, id: \.self) { item in
TitleWithDescriptionView(title: item.title, description: item.description)
.tag(item.index)
}
}
.onChange(of: selectedPageIndex) { newValue in
debugPrint("[a]: new value \(newValue)")
}
.tabViewStyle(.page(indexDisplayMode: .always))
.indexViewStyle(.page(backgroundDisplayMode: .never))
}
}
}