I have the class SliderPgaeViewController: UIPageViewController
with scroll transition style as follows:
class SliderPgaeViewController: UIPageViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource, PlayerUpdatePageControllerDelegate {
var lastPendingIndex: Int = 0
var sliderPageDelegate: SliderPageDelegate? = nil
let playerManager = PlayerManager.getInstance()
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
self.delegate = self
setViewControllers([createViewController(index: playerManager.getCurrentIndex())!], direction: .forward, animated: true, completion: nil)
lastPendingIndex = playerManager.getCurrentIndex()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func presentationCount(for pageViewController: UIPageViewController) -> Int {
return playerManager.getSongsCount()
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
if let vc = viewController as? PlayerImageViewController {
if (vc.index == 0){
return nil
}
return createViewController(index: vc.index! - 1)
}
return nil
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
if let vc = viewController as? PlayerImageViewController {
if (vc.index == playerManager.getSongsCount() - 1){
return nil
}
return createViewController(index: vc.index! + 1)
}
return nil
}
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]){
if let vc = pendingViewControllers[0] as? PlayerImageViewController {
self.lastPendingIndex = vc.index!
}
}
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool,previousViewControllers: [UIViewController],transitionCompleted completed: Bool) {
print("before completion : \(self.lastPendingIndex)")
if(completed){
print("completed : \(self.lastPendingIndex)")
if (viewControllers?.first as? PlayerImageViewController) != nil {
sliderPageDelegate?.updateSong(index: self.lastPendingIndex, dir: 0)
}
}
}
private func createViewController(index i: Int) -> UIViewController?{
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PlayerImageController") as! PlayerImageViewController
vc.index = i
vc.image = playerManager.getSong(index: i).image
return vc
}
...
I am using this page controller to display the thumbnail of a song in a music player. And when the user turn a page the player changes the song playing by calling sliderPageDelegate?.updateSong(index: self.lastPendingIndex, dir: 0)
in pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool,previousViewControllers: [UIViewController],transitionCompleted completed: Bool)
When I'm turning the page forward and then immediately backward, the page is turning correctly (first forward then backward); however, sliderPageDelegate?.updateSong(index: self.lastPendingIndex, dir: 0)
is only being called in the forward direction.
So, if we have list of songs (A, B, C, ...)
and we are currently at song A
. When the user swipes forward, the thumbnail changes to B's
thumbnail and the player updates the song to B
. However, if the forward swipe was followed by a backward swipe quickly, then the thumbnail changes to A
but the song remains B
Update:
if A
has index = 0
and B
has index = 1
, moving A->B->A
quickly will print the following:
before completion : 1
before completion : 1
completed : 1
I have added PageControllerDelegate
in your code and introduce two new methods. Then implement these delegates in your UIPageViewController
class and then in PlayerImageViewController
class invoke both methods in viewWillAppear
and viewWillDisappear
. Now remove you didFinishAnimation
method and write that code in viewControllerIsBeingDisplay
.
For deeper knowledge review this code.
class PlayerImageViewController: UIViewController {
var index: Int?
var image: UIImage?
weak var delegate: PageControllerDelegate?
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if let del = self.delegate {
del.viewControllerIsBeingHide(self)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let del = self.delegate {
del.viewControllerIsBeingDisplay(self)
}
}
}
protocol SliderPageDelegate {
func updateSong(index: Int, dir: Int)
}
protocol PageControllerDelegate {
func viewControllerIsBeingHide(_ viewController: PlayerImageViewController)
func viewControllerIsBeingDisplay(_ viewController: PlayerImageViewController)
}
class SliderPgaeViewController: UIPageViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource, PageControllerDelegate {
var lastPendingIndex: Int = 0
var sliderPageDelegate: SliderPageDelegate? = nil
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
self.delegate = self
setViewControllers([createViewController(index: playerManager.getCurrentIndex())!], direction: .forward, animated: true, completion: nil)
lastPendingIndex = playerManager.getCurrentIndex()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func presentationCount(for pageViewController: UIPageViewController) -> Int {
return playerManager.getSongsCount()
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
if let vc = viewController as? PlayerImageViewController {
if (vc.index == 0){
return nil
}
return createViewController(index: vc.index! - 1)
}
return nil
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
if let vc = viewController as? PlayerImageViewController {
if (vc.index == playerManager.getSongsCount() - 1){
return nil
}
return createViewController(index: vc.index! + 1)
}
return nil
}
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]){
if let vc = pendingViewControllers[0] as? PlayerImageViewController {
self.lastPendingIndex = vc.index!
}
}
private func createViewController(index i: Int) -> UIViewController?{
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PlayerImageController") as! PlayerImageViewController
vc.index = i
vc.delegate = self
// vc.image = playerManager.getSong(index: i).image //Commented becoz i do not have this file
return vc
}
var previousVCIndex = 0
func viewControllerIsBeingHide(_ viewController: PlayerImageViewController) {
previousVCIndex = viewController.index!
}
func viewControllerIsBeingDisplay(_ viewController: PlayerImageViewController) {
if let del = sliderPageDelegate {
del.updateSong(index: previousVCIndex, dir: 0)
}
}
}