Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing UIPageViewController's page programmatically doesn't update the UIPageControl

In my custom UIPageViewController class:

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        self.model = [[BSTCMWelcomingPageViewModel alloc] init];
        self.dataSource = self.model;
        self.delegate = self;

        self.pageControl = [UIPageControl appearance];
        self.pageControl.pageIndicatorTintColor = [UIColor lightGrayColor];
        self.pageControl.currentPageIndicatorTintColor = [UIColor blackColor];
    }
    return self;
}

Then I programmatically set the current ViewController when a button is hit:

- (void)scrollToNext
{
    UIViewController *current = self.viewControllers[0];
    NSInteger currentIndex = [self.model indexForViewController:current];
    UIViewController *nextController = [self.model viewControllerForIndex:++currentIndex];
    if (nextController) {
        NSArray *viewControllers = @[nextController];
        // This changes the View Controller, but PageControl doesn't update
        [self setViewControllers:viewControllers
                       direction:UIPageViewControllerNavigationDirectionForward
                        animated:YES
                      completion:nil];
        //Nothing happens!
        [self.pageControl setCurrentPage:currentIndex];

        //Error: _installAppearanceSwizzlesForSetter: Not a setter!
        [self.pageControl updateCurrentPageDisplay];
    }
}

If I can't do this with the UIPageControl that "belongs" to my UIPageViewController I will just try to make my own. But it would be nice if this was possible tho!

like image 793
Johannes Avatar asked Mar 21 '14 09:03

Johannes


3 Answers

to update your UIPageControl indicator, you need to implement one data source method of UIPageViewController (the UIPageViewControllerDataSource method) :

-(NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController

This method is responsible for updating the page control indicator (when you use UIPageViewController). You only need to return the currentpage value in this method. The Method gets called by default when you use/make a call for setViewControllers on your custom UIPageViewController.

So the chunk of code that you need to write is:

- (void)scrollToNext
{
    UIViewController *current = self.viewControllers[0];
    NSInteger currentIndex = [self.model indexForViewController:current];
    UIViewController *nextController = [self.model viewControllerForIndex:++currentIndex];
    if (nextController) {
        NSArray *viewControllers = @[nextController];
       // This changes the View Controller and calls the presentationIndexForPageViewController datasource method
       [self setViewControllers:viewControllers
                   direction:UIPageViewControllerNavigationDirectionForward
                    animated:YES
                  completion:nil];
}

- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
{
    return currentIndex;
}

Hope this solves your problem. :)

like image 165
anshul Avatar answered Oct 31 '22 02:10

anshul


As mentioned in accepted answer, you need to implement

- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController

But for me it was enough to use it like this:

Objective-C:

- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController {
    // The selected item reflected in the page indicator.
    return [self.controllers indexOfObject:[pageViewController.viewControllers firstObject]];
}

Swift 3+:

func presentationIndex(for pageViewController: UIPageViewController) -> Int {
        guard let index = viewControllers?.index(of: (pageViewController.viewControllers?.first)!) else { return 0 }
        return index
}

Without the need to remember the current index. Where self.controllers is an NSArray of UIViewControllers displayed in given UIPageViewController. I'm not sure how exactly your BSTCMWelcomingPageViewModel works, but it should be easy to adjust.

like image 24
micromanc3r Avatar answered Oct 31 '22 03:10

micromanc3r


Xamarin/C# Solution

I had this problem in Xamarin, here is my version of @micromanc3r's solution:

public class PageViewControllerDataSource : UIPageViewControllerDataSource
{
    UIViewController[] pages;

    public PageViewControllerDataSource(UIViewController[] pages)
    {
        this.pages = pages;
    }

...

    public override nint GetPresentationIndex(UIPageViewController pageViewController)
    {
        return Array.IndexOf(pages, pageViewController.ViewControllers[0]);
    }
}
like image 25
Mark Moeykens Avatar answered Oct 31 '22 03:10

Mark Moeykens