I'm looking for a reliable way to keep track of UIPageViewController current index.
The problem is well known; Although viewControllers are being presented properly, it hard to keep track of the current index.
I thought it will be good to refresh this topic across SO community since it remains unsolved for some reason
I've browsed through many threads here, but most answers are outdated or marked as unreliable(The result depends on if user did a full swipe or just half swiped etc)
I've visited this thread, but it doesn't provide any explicitly correct answer.
I've tried:
1) Keeping track of viewController's view tag - link - always returns 0
2) Looking at index variable in both UIPageViewController methods, viewControllerBeforeViewController
and viewControllerAfterViewControlle
its results is unpredictable, sometimes it skips over one index etc.
Have anybody come up with a good way, reliable way to keep track of UIPageCiewController index to make use of it(for example print current index)?
I'd appreciate both obj-c and swift implementation, but swift is the one I'm looking for.
This is for ObjC
ParentViewController
#import "PagesViewController.h"
// Delegate: PageViewDelegate
// Declared inside `PagesViewController`
//
@interface ParentViewController () <UIPageViewControllerDataSource, UIPageViewControllerDelegate, PageViewDelegate>
@property (nonatomic) UIPageViewController *pageViewController;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageViewController.dataSource = self;
self.pageViewController.view.frame = self.view.frame;
// im setting page 3 as the default page
//
[self.pageViewController setViewControllers:[NSArray arrayWithObject:[self viewControllerAtIndex:3]] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger index = [(PagesViewController *)viewController index];
if (index == 0) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
NSUInteger index = [(PagesViewController *)viewController index];
index++;
if (index == 5) {
return nil;
}
return [self viewControllerAtIndex:index];
}
- (PagesViewController *)viewControllerAtIndex:(NSInteger)index
{
PagesViewController *vc = [[PagesViewController alloc] init];
// set delegate here..
//
vc.delegate = self;
// other data
//
vc.index = index;
vc.titleLabel = [NSString stringWithFormat:@"Screen :%ld", (long)index];
return vc;
}
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
{ // The number of items reflected in the page indicator. return x; }
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
{ // The selected item reflected in the page indicator. return x; }
// This is what you need
//
- (void)viewController:(id)VC didShowWithIndex:(long)index
{
NSLog(@"didShowWithIndex: %ld", index);
}
PagesViewController.h
@protocol PageViewDelegate <NSObject>
- (void)viewController:(id)VC didShowWithIndex:(long)index;
@end
@interface PagesViewController : UIViewController
@property (weak) id <PageViewDelegate> delegate;
@property (nonatomic) NSInteger index;
@property (nonatomic) NSString *titleLabel;
@end
PagesViewController.m
@implementation PagesViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
UILabel *titleLabel = [[UILabel alloc] initWithFrame:self.view.frame];
titleLabel.textAlignment = NSTextAlignmentCenter;
titleLabel.textColor = [UIColor whiteColor];
titleLabel.text = self.titleLabel;
[self.view addSubview:titleLabel];
}
// Trigger delegate here
//
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.delegate viewController:self didShowWithIndex:self.index];
}
@end
Like @0yeoj suggested, delegation design patter is the solution here. It requires a bit of thinking outside the box.
Let's add protocol IndexDelegate and modify a bit PageContentViewController
protocol IndexDelegate {
func showIndex(index:Int)
}
import UIKit
class PageContentViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
var delegate:IndexDelegate?
var pageIndex:Int = 0
var imageFile:String!
override func viewDidLoad() {
super.viewDidLoad()
self.imageView.image = UIImage(named: self.imageFile)
}
override func viewDidAppear(animated: Bool) {
self.delegate!.showIndex(self.pageIndex)
}
now in our parent view controller we conform to protocol
func showIndex(index: Int) {
print(index)
}
don't forget to set yourPageContentViewControllerInstance.delegate = self
and inherit protocol YourParentViewController:UIViewController, UIPageViewControllerDataSourceDelegate, IndexDelegate {}
That's it! Works perfectly and reliably and doesn't lag at all!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With