Tom Elliott
Tom Elliott

Reputation: 1926

Embedding a UIPageViewController in a UIViewController stops paging

I'm working on a modally-presented lightbox and I'm having trouble embedding the UIPageViewController in the parent view controller (to allow for "floating" elements that are not paged).

Below is the source for the containing UIViewController. Its Xib contains a UIButton and a UIView with an outlet called workingArea.

The array of views (vc) is populated with a test class that places a solid-color image in the center of the view.

@interface LightboxContainerViewController ()

@property (nonatomic) NSArray *vcs;

@end

@implementation LightboxContainerViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.

    UIPageViewController *lb = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];

    lb.dataSource = self;

    self.vcs = @[
                 [[LightboxViewController alloc] initWithNibName:@"LightboxViewController" bundle:nil andImage:[UIImage imageWithColor:[UIColor redColor]]],
                 [[LightboxViewController alloc] initWithNibName:@"LightboxViewController" bundle:nil andImage:[UIImage imageWithColor:[UIColor greenColor]]],
                 [[LightboxViewController alloc] initWithNibName:@"LightboxViewController" bundle:nil andImage:[UIImage imageWithColor:[UIColor blueColor]]]
                 ];

    [lb setViewControllers:@[self.vcs[0]]
                   direction:UIPageViewControllerNavigationDirectionForward
                    animated:NO completion:nil];

    lb.view.frame = self.workingArea.bounds;
    [self.workingArea addSubview:lb.view];
}

-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController
     viewControllerBeforeViewController:(UIViewController *)viewController
{
    NSUInteger currentIndex = [self.vcs indexOfObject:viewController];

    if(currentIndex == 0){
        return nil;
    }
    return [self.vcs objectAtIndex:--currentIndex];
}

-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController
      viewControllerAfterViewController:(UIViewController *)viewController
{
    NSUInteger currentIndex = [self.vcs indexOfObject:viewController];
    if(currentIndex == self.vcs.count - 1){
        return nil;
    }
    // Output selected VC
    return [self.vcs objectAtIndex:++currentIndex];
}

-(NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
{
    return self.vcs.count;
}

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

#pragma Modal view management

- (void) presentModal {
    [[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentViewController:self animated:YES completion:nil];
    [UIView animateWithDuration:0.3 animations:^{
        [[UIApplication sharedApplication] setStatusBarHidden:YES];
    }];
}

- (void) dismissModal {
    [self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
    [UIView animateWithDuration:0.3 animations:^{
        [[UIApplication sharedApplication] setStatusBarHidden:NO];
    }];
}

#pragma mark UI interaction

- (IBAction)closePressed:(id)sender {
    [self dismissModal];
}

#pragma mark UIPageViewControllerDatasource

-(UIViewController *)viewControllerAtIndex:(NSUInteger)index
{
    return self.vcs[index];
}

@end

The first UIViewController of the three shows up fine, and there are three dots in the scrolling indicator, but I cannot swipe between pages.

I've set breakpoints, and viewControllerBeforeViewController/viewControllerAfterViewController are never called, although presentationIndexForPageViewController is.

This code seems to work fine when the datasource methods are included directly in a UIPageViewController, it only gets stuck like this when embedded in a parent UIViewController.

Upvotes: 0

Views: 1335

Answers (2)

Tom Elliott
Tom Elliott

Reputation: 1926

For the sake of completeness, here's the change I ended up making and why (new lines marked NEW):

- (void)viewDidLoad {

    // ...

     UIPageViewController *lb = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];

    lb.dataSource = self;

    // Populate self.vs here

    // NEW: Added this line to ensure we retain a reference to lb
    [self addChildViewController:lb];

    [lb setViewControllers:@[self.vcs[0]]
                   direction:UIPageViewControllerNavigationDirectionForward
                    animated:NO completion:nil];

    // Set page view controller's view's frame to match host view's frame
    lb.view.frame = self.workingArea.bounds;

    // NEW: Added this line to notify lb of what's happening
    [lb didMoveToParentViewController:self];

    [self.workingArea addSubview:lb.view];
}

This is the same pattern as used for Container Views, and ensures that we retain a reference to the UIPageViewController so that the delegate can be found on interaction.

I don't need to do any additional work with the UIPageViewController once loaded, so this is sufficient for my purpose.

Upvotes: 1

tuledev
tuledev

Reputation: 10327

lb is released after alloc. So it can't do anything

UIPageViewController *lb = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];

You should create a var in .h or in .m file like:

@interface LightboxContainerViewController ()
{
   UIPageViewController *lb
}

@property (nonatomic) NSArray *vcs;

@end

then

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.



       lb = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
        // .....
    }

Upvotes: 1

Related Questions