2
votes

I am making an iOS application that has a UIPageViewController that is loaded with a default page if there aren't any others added yet, and a user can add pages as he progresses through the app. However, the initial view never changes as others are added.

I've tried the answers from these questions:
Is it possible to Turn page programmatically in UIPageViewController?
Changing UIPageViewController's page programmatically doesn't update the UIPageControl
Removing a view controller from UIPageViewController
Refresh a UIPageViewController

None of them work for me. The view still remains at the initial page until I reload the application, after which, the pages show fine, and I can add as many as I want.

This is the code I have for making the PageView and the pages

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];

    self.pageController.dataSource = self;
    [[self.pageController view] setFrame:[[self pageControllerView] bounds]];

    UIViewController *initialViewController = [self viewControllerAtIndex:0];

    __block Page1ViewController *blocksafeSelf = self;

    // This doesn't work either... :(
    void (^completionBlock)(BOOL) = ^(BOOL finished)
    {
        // It seems that whenever the setViewControllers:
        // method is called with "animated" set to YES, UIPageViewController precaches
        // the view controllers retrieved from it's data source meaning that
        // the dismissed controller might not be removed. In such a case we
        // have to force it to clear the cache by initiating a non-animated
        // transition.
        usleep(1);
        dispatch_async(dispatch_get_main_queue(), ^(){
            [blocksafeSelf.pageController setViewControllers:@[initialViewController]
                                      direction:UIPageViewControllerNavigationDirectionForward
                                       animated:NO
                                     completion:nil];
        });
    };

    [self.pageController setViewControllers:@[initialViewController]
                              direction:UIPageViewControllerNavigationDirectionForward
                               animated:YES
                             completion:completionBlock];

    [self addChildViewController:self.pageController];
    [[self view] addSubview:[self.pageController view]];
    [self.pageController didMoveToParentViewController:self];
}

- (void)reloadViews
{
    [[self childViewControllers] makeObjectsPerformSelector:@selector(removeFromParentViewController)];
    [[self.view subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];

    [self.pageController willMoveToParentViewController:nil];
    [self.pageController removeFromParentViewController];
    [self.pageController.view removeFromSuperview];
    self.pageController = nil;
    self.pageController = [[UIPageViewController alloc] init];

    [self.view setNeedsDisplay];
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
    NSUInteger index = ((SomethingViewController *)viewController).index;
    index++;

    if (index >= [Settings somethings].count)
    {
        return nil;
    }

    return [self viewControllerAtIndex:index];
}

- (UIViewController *)viewControllerAtIndex:(NSUInteger)index
{
    UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Storyboard_iPhone"
                                              bundle:nil];
    if ([Settings somethings].count == 0 && index == 0)
    {
        NoSomethingViewController *vc = [sb instantiateViewControllerWithIdentifier:@"NoSomethingViewController"];
        vc.index = index;
        return vc;
    }

    SomethingViewController *childViewController = [sb instantiateViewControllerWithIdentifier:@"SomethingViewController"];
    childViewController.something = [[Settings somethings] somethingAtIndex:index];
    childViewController.index = index;

    return childViewController;
}

When a new page should be created, by adding a something in the somethings array, I call reloadViews from the View controller that did the adding of the something. The code then hits the second part of viewControllerAtIndex, but that is not shown on the page that I see on the phone, as I still see the NoSomethingViewController and it's view.

If you need more code, I'll provide.

4
what you are trying to do? you are trying to scroll and in UIPageIndicator page is not changing or you are trying to add extra page once UIPageViewController has loaded the page?Gyanendra
I am trying to reload page view controller to show a different page, when I add a somethingReapo
I don't think you can reload page view controller after it is loaded. One thing you can do is if some thing is getting changed then remove the page View controller from superview and add it again so dynamic pages will be loaded if some thing will change.Gyanendra
I do at the beginning of the viewDidLoad method. if the page controller already exists, remove it; recreate it. It doesn't do anything.Reapo
Yes but when you have to add new pages in page view controller at that time also remove it from superview and add the page view controller again, by doing this pageviewController delegate will be called again and in pageviewcontroller number of pages will automatically get refreshed.Gyanendra

4 Answers

3
votes

add the following code in the pageViewController viewWillAppear method

dataSource = self

and in the viewWillDisappear add

dataSource = nil

this will force the pageViewController to reload its dataSource

0
votes

To show the current dot, dont forget you have to update the page indicator

- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController

Example how to update your UIPageControl indicator https://stackoverflow.com/a/22576250/3897011

0
votes

After a long time and after wasting a support ticket with Apple, I decided to go with another approach.

In my Storyboard I created 2 different navigation controllers, one for each case (if there are somethings and if there aren't any), and I have an initial view Controller that, on viewDidAppear, instantiates one of the two and presents it. This way, I make sure that the entire navigation controller gets reloaded correctly.

UINavigationController *nc;

if ([Settings somethings].count)
{
    nc = [self.storyboard instantiateViewControllerWithIdentifier:@"NavigationController"];
}
else
{
    nc = [self.storyboard instantiateViewControllerWithIdentifier:@"NoSomethingNavigationController"];
}

self.nc = nc;

[self presentViewController:nc animated:NO completion:nil];
-1
votes

In order to reload UIPageViewController you can use the following code:

[self.pageController setViewControllers:@[yourCurrentController]
                                      direction:UIPageViewControllerNavigationDirectionForward
                                       animated:NO
                                     completion:nil];

Also please implement

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController

method.