Reputation: 1926
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
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
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