Page View is common feature in any mobile application. There are some methods that help implementing page view in SwiftUI, but they are not useful enough to deal with real project. As a result, in this post I’ll talk about these methods’ limits and introduce a solution for implementing page view in a SwiftUI project.
Contents
The requirement
When implementing pager view I usually need the solution satisfy the following requirements:
- Support loop.
- Allow customize item size.
- Can customize
UIPageControl.
Currently available solutions
To solve this problem I have search on the internet there are 3 possible solutions to implement page view in SwiftUI:
- Using
tabViewStyle() - Interfacing
UIPageViewController - Using library SwiftUIPager
Let’s take a look at how these methods work and check their pros and cons.
Using tabViewStyle() to implement page view in SwiftUI
The first method to implement page view in SwiftUI uses TabView with modifier tabViewStyle() :
struct ContentView: View {
var body: some View {
TabView {
Text("First")
Text("Second")
Text("Third")
Text("Fourth")
}
.tabViewStyle(.page)
}
}
This solution is simple. But it does not satisfy any of my requirements including loop, custom size or custom UIPageControl.
Interfacing UIPageViewControllerto implement page view in SwiftUI
The second method to implement page view in SwiftUI use UIPageController inside SwiftUI wrapper:
struct PageViewController<Page: View>: UIViewControllerRepresentable {
var pages: [Page]
func makeUIViewController(context: Context) -> UIPageViewController {
let pageViewController = UIPageViewController(
transitionStyle: .scroll,
navigationOrientation: .horizontal)
return pageViewController
}
func updateUIViewController(_ pageViewController: UIPageViewController, context: Context) {
pageViewController.setViewControllers(
[UIHostingController(rootView: pages[0])], direction: .forward, animated: true)
}
}
This solution is also the same as the first, it does not satisfy any requirements. So it is out of the table.
Using library SwiftUIPager to implement page view in SwiftUI
SwiftUIPager is a library for implementing pager view in SwiftUI using SwiftUI view. It provides many features and satisfy all the requirements. Unfortunately there is a bug when using loop pager view:
As you can see at the end of the video the pager view’s content disappear and cannot scroll any. It’s been around more than 3 months since I found out this bug and nothing has been done to fix this. So we cannot use this solution too.
My solution to implement page view in SwiftUI
As described above, there is no solution that satisfy all requirements without any bugs. Because of that I decided to use a UIKit library and integrate it into SwiftUI: FSPagerView to implement page view in SwiftUI. Why I choose this library:
- It satisfy all my requirements.
- FSPagerView work stably without any bugs.
- It supports customize
UIPageControl. - Simple API.
After sometimes integrate FSPagerView into SwiftUI, I have created a repo, you can check try it for yourself. Here is sample code for using FSPagerView in SwiftUI from the repo:
struct ContentView: View {
private struct TutorialItem: Identifiable {
let id: UUID = UUID()
let image: String
}
private let images: [TutorialItem] = [
TutorialItem(image: "1"),
TutorialItem(image: "2"),
TutorialItem(image: "3"),
TutorialItem(image: "4"),
TutorialItem(image: "5"),
TutorialItem(image: "6"),
TutorialItem(image: "7"),
]
@State var currentPage: Int = 0
var body: some View {
ZStack(content: {
FSPagerViewSUI($currentPage, images) { item in
Image(item.image)
.resizable()
.frame(
maxWidth: .infinity,
maxHeight: .infinity
)
}
VStack(alignment: .center, spacing: nil, content: {
FSPageControlSUI(currentPage: $currentPage)
.numberOfPages(images.count)
.contentHorizontalAlignment(.right)
.contentInsets(UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)) .frame(maxWidth: .infinity)
.frame(height: 20)
.background(Color.black.opacity(0.5))
})
.frame(
maxWidth: .infinity,
maxHeight: .infinity,
alignment: .bottomTrailing
)
})
.aspectRatio(375.0/193.0, contentMode: .fit)
}
}
Wraps Up
So in this post I have explained my experiences and solution when implementing pager view in SwiftUI. This may change in the future and I’ll update this post if changes are available.