UIPageViewController manual pagination not working properly.
Automatic pagination working fine, but when we rotate manually it’s not working properly.
My ViewController.Swift code
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var contentView: UIView!
@IBOutlet weak var pageControl: UIPageControl!
let myDataSource = ["Img1", "Img2", "Img3", "Img4"]
let urlDataSource = ["https://fabric.io/", "https://about.gitlab.com/", "https://developer.apple.com/", "https://fast.com/"]
var currentVCIndex = 0
var timer = Timer()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
configurePageViewController()
timerStart()
}
func timerStart() {
timer.invalidate()
timer = Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(configurePageViewController), userInfo: nil, repeats: true)
}
@objc func configurePageViewController() {
guard let pageVc = storyboard?.instantiateViewController(identifier: "CustomPageViewController") as? CustomPageViewController else {
return
}
pageVc.delegate = self
pageVc.dataSource = self
addChild(pageVc)
pageVc.didMove(toParent: self)
pageVc.view.translatesAutoresizingMaskIntoConstraints = false
pageControl.layer.zPosition = 1;
pageControl.numberOfPages = myDataSource.count
pageControl.currentPageIndicatorTintColor = .lightGray
pageControl.pageIndicatorTintColor = .white
contentView.addSubview(pageVc.view)
let views : [String : Any] = ["pageView": pageVc.view!]
contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[pageView]-0-|",
options: NSLayoutConstraint.FormatOptions(rawValue: 0),
metrics: nil,
views: views))
contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[pageView]-0-|",
options: NSLayoutConstraint.FormatOptions(rawValue: 0),
metrics: nil,
views: views))
guard let startingVc = detailVCAt(index: currentVCIndex) else {
return
}
pageVc.setViewControllers([startingVc], direction: .forward, animated: true)
increaseCount()
}
func increaseCount() {
pageControl.currentPage = currentVCIndex
if currentVCIndex == 3 {
currentVCIndex = 0
} else {
currentVCIndex = currentVCIndex+1
}
}
func detailVCAt(index: Int) -> DataViewController? {
if index >= myDataSource.count || myDataSource.count == 0 {
return nil
}
guard let dataVC = storyboard?.instantiateViewController(identifier: "DataViewController") as? DataViewController else {
return nil
}
dataVC.index = index
dataVC.displayImgName = myDataSource[index]
dataVC.redirectURL = urlDataSource[index]
return dataVC
}
}
extension ViewController: UIPageViewControllerDelegate, UIPageViewControllerDataSource {
func presentationIndex(for _: UIPageViewController) -> Int {
return myDataSource.count
}
func presentationCount(for _: UIPageViewController) -> Int {
return myDataSource.count
}
func pageViewController(_: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
let dataVc = viewController as? DataViewController
guard var currentIndex = dataVc?.index else {
return nil
}
currentVCIndex = currentIndex
if currentIndex == 0 {
return nil
}
currentIndex -= 1
pageControl.currentPage = currentVCIndex
// timerStart()
// increaseCount()
return detailVCAt(index: currentIndex)
}
func pageViewController(_: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let dataVc = viewController as? DataViewController
guard var currentIndex = dataVc?.index else {
return nil
}
if currentIndex == myDataSource.count {
return nil
}
currentIndex += 1
currentVCIndex = currentIndex
pageControl.currentPage = currentVCIndex
// timerStart()
// increaseCount()
return detailVCAt(index: currentIndex)
}
}
My DataViewController.Swift code
import UIKit
class DataViewController: UIViewController {
@IBOutlet weak var btn: UIButton!
var displayImgName :String?
var redirectURL :String?
var index: Int?
override func viewDidLoad() {
super.viewDidLoad()
btn.setImage(UIImage.init(named: displayImgName ?? ""), for: .normal)
}
@IBAction func onClickBtn(_ sender: UIButton) {
if let url = URL(string: redirectURL ?? ""), UIApplication.shared.canOpenURL(url) {
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
UIApplication.shared.openURL(url)
}
}
}
}
My CustomPageViewController.Swift code
import UIKit
class CustomPageViewController: UIPageViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
My StoryBoard image
2
Answers
In your code,
currentIndex
is getting wrong. You can use the following delegate method to get correctcurrentIndex
.Also in your scheduled timer
configurePageViewController
methods call every 5-sec. This method creates a new instance ofUIPageViewController
at the time of method call and adds a child view, this will cause memory issues in the future.I would suggest if you add
UIPageViewController
embedded in ContainerView using a storyboard. You can find attached Screenshot.I have a better solution for your scenario. Please find the following code:
My ViewController.Swift code:
My DataViewController.Swift code:
My CustomPageViewController.Swift code:
My StoryBoard image
The issue in your code is that you cannot determine the index of the currently visible view controller, inside
pageViewController(_:viewControllerBefore:)
andpageViewController(_:viewControllerAfter:)
functions of theUIPageViewControllerDataSource
, due to the fact that those delegate functions may get called more than once each time you scroll.For example, if you are currently in index 0 and you scroll to index 1, the
pageViewController(_:viewControllerAfter:)
function will be called 2 times, one for index 1 and one for index 2 to preload the next page.Having said that, you can pretty much find out the index of the currently visible view controller following this answer and using
pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:)
function of theUIPageViewControllerDelegate
, but with a small modification that fits your needs:Also, there is no need to implement
presentationIndex(for:)
andpresentationCount(for:)
functions ofUIPageViewControllerDataSource
since you are using a customUIPageControl
. So, your extension may look like this: