UIPageViewController not resizing its child view controllers on rotation - ios

I am trying to use UIPageViewController with view controllers added to it, problem is if I launch the app in portrait mode it appears perfectly like this:
but if I rotate the device to landscape mode it appears like this:
Though pagination control has resized properly, view of added view controller has not resized properly.
Below is the code which I have used to add respective view controller as root view controller in AppDelegate:
pagesContainerViewController = [[RWPagesContainerViewController alloc] initWithNibName:#"RWPagesContainerViewController" bundle:nil];
[pagesContainerViewController loadPaginationControlAtIndex:0];
self.window.rootViewController = pagesContainerViewController;
Here is the implementation of loadPaginationControlAtIndex method:
- (void)loadPaginationControlAtIndex:(RWPaginationView)viewIndex {
_pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
FirstViewController *firstViewController = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
ThirdViewController *thirdViewController = [[ThirdViewController alloc] initWithNibName:#"ThirdViewController" bundle:nil];
_subviewControllers = #[firstViewController, secondViewController, thirdViewController];
[self.pageController setViewControllers:#[_subviewControllers[viewIndex]] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
[self addChildViewController:self.pageController];
[[self view] addSubview:[self.pageController view]];
UIView *insertedView = self.pageController.view;
insertedView.translatesAutoresizingMaskIntoConstraints = NO;
self.view.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[insertedView]|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(insertedView)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[insertedView]|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(insertedView)]];
[self.view layoutIfNeeded];
self.pageController.dataSource = self;
}
Am I missing anything? Please suggest.

when the application loads or when your view loads:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]
addObserver:self selector:#selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:[UIDevice currentDevice]];
Then add the following method:
- (void) orientationChanged:(NSNotification *)note
{
[self.pageController setViewControllers:#[_subviewControllers[currentIndex]] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
}

Related

Why ContentVC's viewWill/DidAppear is called before its parent(PageVC)?

In my case, I use ViewController as parent of PageViewController. And it also be the dataSource of PageViewController by providing ContentViewController.
It's strange that ContentViewController's -viewWill/DidAppear: is called before it's parent, here is what I got from console:
[ContentViewController viewWillAppear:]
[ContentViewController viewDidAppear:]
[ViewController viewWillAppear:]
[PageViewController viewWillAppear:]
[ViewController viewDidAppear:]
[PageViewController viewDidAppear:]
Here are some code from ViewController.m:
- (void)viewDidLoad {
[super viewDidLoad];
PageViewController *pageVC = [[PageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];;
pageVC.dataSource = self;
[pageVC setViewControllers:#[[self contentViewControllerWithIndex:0]]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO completion:nil];
pageVC.view.backgroundColor = [UIColor whiteColor];
pageVC.view.frame = self.view.bounds;
[self addChildViewController:pageVC];
[self.view addSubview:pageVC.view];
[pageVC didMoveToParentViewController:self];
}
-(ContentViewController *)contentViewControllerWithIndex:(NSInteger )index {
ContentViewController *vc = [[ContentViewController alloc] init];
vc.index = index;
return vc;
}
Thanks.
If you go through line by line of your code
This line just alloc your PageViewController. It has actually not added it on top of your ViewController. So ViewWillAppear for PageViewController will not get called here.
Code:
PageViewController *pageVC = [[PageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
Below line is calling [self contentViewControllerWithIndex:0] which will be allocating the ContentViewController also adding it on PageVC so ViewWillAppear for ContentViewController is called
Code:
[pageVC setViewControllers:#[[self contentViewControllerWithIndex:0]]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO completion:nil];
Below line is adding PageVC as childViewControllerof ViewController. So once the ViewWillAppear of ViewController will be called then only it can call ViewWillAppear of PageVC and add it as its childView.
Code:
[self addChildViewController:pageVC];
[self.view addSubview:pageVC.view];
[pageVC didMoveToParentViewController:self];

Add Custom View on UIPageViewController

I want to add a Custom View (red View) on the bottom of my UIPageViewController like this:
Because i want some Standard Text which is displayed on every View of my UIPageViewController. Everythings works fine, but my Custom VIew is not visible, this is what i tried:
- (void)viewDidLoad
{
self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageController.dataSource = self;
[[self.pageController view] setFrame:[[self view] bounds]];
FirstTutorialViewController *initialViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = [NSArray arrayWithObject:initialViewController];
[self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
[self addChildViewController:self.pageController];
[[self view] addSubview:[self.pageController view]];
[self.pageController didMoveToParentViewController:self];
//Here i try to set the Custom view:
[[self.pageController view] addSubview:[self customView]];
Don't add self customView to the page controller, and be sure to set its frame first.
Instead, resize the page controller to allow space at the bottom for the custom view and add both to your main view.

Delegate between UIViewControllers

I have following structure of ViewControllers:
PageViewController contains PhotoViewController and VideoViewController, that changing programmatically, so there no any segues.
I want allow VideoControlViewController to use methods from CameraViewController. I tried to use following code:
self.videoControlViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"videoControlViewController"];
self.videoControlViewController.delegate = self;
It don't works because method "instantiateViewControllerWithIdentifier" creates new instance of VideoViewController. Here is topic with the same problem that I found:
http://iphonedevsdk.com/forum/iphone-sdk-development/109543-string-becomes-nil-after-viewdidload-with-protocol-and-delegate.html
How can I point self.VideoControlViewController to its instance from storyboard if there no any segues or transitions?
- (void)viewDidLoad {
[super viewDidLoad];
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.viewControllers = #[#"photoControlViewController", #"videoControlViewController"];
self.pageViewController.dataSource = self;
[[self.pageViewController view] setFrame:[[self view] bounds]];
[self.pageViewController setViewControllers:[NSArray arrayWithObject:[self viewControllerAtIndex:[self.viewControllers indexOfObject:#"photoControlViewController"]]] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
[self addChildViewController:self.pageViewController];
[[self view] addSubview:[self.pageViewController view]];
[self.pageViewController didMoveToParentViewController:self];
}

Dynamically reload UIPageViewController after dataSource changed

so I'm trying to create an ibooks-like reader and I need to update the contents of the UIPageViewController dynamically after I get the data from the webservice. For a long series of reasons I have to instantiate it at the beginning and then update it when the data comes.
I'm creating it like this:
NSDictionary *options =
[NSDictionary dictionaryWithObject:
[NSNumber numberWithInteger:UIPageViewControllerSpineLocationMin]
forKey: UIPageViewControllerOptionSpineLocationKey];
self.pageController = [[UIPageViewController alloc]
initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl
navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
options: options];
self.pageController.dataSource = self;
self.pageController.delegate = self;
[[self.pageController view] setFrame:[[self view] bounds]];
MovellaContentViewController *initialViewController = [self viewControllerAtIndex:0];
self.controllers = [NSArray arrayWithObject:initialViewController];
[self.pageController setViewControllers:self.controllers
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
[self addChildViewController:self.pageController];
[[self view] addSubview:[self.pageController view]];
[self.pageController didMoveToParentViewController:self];
and then I just set self.controllers = newControllersArray;
I'm looking for something like reloadData for a UITableViewController, is there such a thing for UIPageViewController?
You have to send setViewControllers:direction:animated:completion: to the pageController again
and give it the first view controller to display:
[self.pageController setViewControllers:[NSArray arrayWithObject:
[self viewControllerAtIndex:0]
]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
If viewControllerAtIndex:does not access self.controllers as I at first assumed, it should probably rather be
[self.pageController setViewControllers:[NSArray arrayWithObject:
[self.controllers objectAtIndex:0]
]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
instead
The main problem was that the webview was intercepting all the user touches and therefore the UiPageViewController wasn't calling the delegate methods. Once set the webview to ignore user touch events everything started to work properly.

Orientation Problem while using insertSubview

I get an orientation problem while using the following to code to display a view on top of a split view.
[window addSubview:aSplitViewController.view];
[window insertSubview:aViewController.view aboveSubview:aSplitViewController.view];
the plain view has a couple of buttons and labels.
So the problem I am facing is that the first view opens in landscape mode but the labels and buttons on the view are in portrait mode.
UPDATE: Here is some code so if anyone wants to see more details...
In my App Delegate
- (void) makeSplitViewController {
NSMutableArray *controllers = [NSMutableArray arrayWithArray:tabBarController.viewControllers];
// First tabbbar item
// detail view
detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
UINavigationController *navDetailView = [[[UINavigationController alloc] initWithRootViewController:detailViewController] autorelease];
navDetailView.hidesBottomBarWhenPushed = YES;
// root view
rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain];
rootViewController.detailViewController = detailViewController;
rootViewController.navigationItem.title = #"List";
UINavigationController *navRootView = [[[UINavigationController alloc] initWithRootViewController:rootViewController] autorelease];
navRootView.hidesBottomBarWhenPushed = YES;
navRootView.navigationBar.barStyle = UIBarStyleBlackTranslucent;
splitViewController = [[UISplitViewController alloc] init];
splitViewController.tabBarItem.title = #"Face Sheet";
splitViewController.tabBarItem.image = [UIImage imageNamed:#"gear1.png"];
splitViewController.navigationItem.title = #"Face Sheet";
splitViewController.viewControllers = [NSArray arrayWithObjects:navRootView, navDetailView, nil];
splitViewController.delegate = detailViewController;
splitViewController.hidesBottomBarWhenPushed = YES;
[controllers addObject:splitViewController];
// Second tabbbar item
scoreViewController = [[ScoreCardViewController alloc] initWithNibName:#"TableViewController" bundle:nil];
scoreViewController.tabBarItem.title = #"Score Card";
scoreViewController.tabBarItem.image = [UIImage imageNamed:#"gear1.png"];
scoreViewController.navigationItem.title = #"Score Card";
[controllers addObject:scoreViewController];
tabBarController.viewControllers = controllers;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Create tabbar
tabBarController = [[UITabBarController alloc] init];
//tabBarController.delegate = self;
// Set window
[window addSubview:splashController.view];
[window insertSubview:tabBarController.view belowSubview:splashController.view];
[self.window makeKeyAndVisible];
application.statusBarOrientation = UIInterfaceOrientationLandscapeRight;
return YES;
}
and here is the code in my SplashScreenView
- (IBAction) proceedButtonClick:(id)sender
{
// Initialize loginpopview
PhysicianLoginViewController *loginViewController = [[PhysicianLoginViewController alloc] init];
popOverController = [[UIPopoverController alloc] initWithContentViewController:loginViewController];
popOverController.popoverContentSize = CGSizeMake(350, 200);
popOverController.delegate = self;
// Set a notification to dismiss it later
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(loginViewControllerDone:) name:#"loginViewControllerDone" object:popOverController.contentViewController];
// Present popover
if ([popOverController isPopoverVisible])
{
[popOverController dismissPopoverAnimated:YES];
}
else
{
[popOverController presentPopoverFromRect:CGRectMake(485, 600, 100, 100) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];
}
}
// Dismiss popview controller and setup the tabbar
- (void)loginViewControllerDone:(NSNotification *)notification{
[[NSNotificationCenter defaultCenter] removeObserver:self];
// Button in content view controller was tapped, dismiss popover...
[self.popOverController dismissPopoverAnimated:YES];
// remove subview
[self.view removeFromSuperview];
// set tabbar
i3EAppDelegate *appDelegate = (i3EAppDelegate *) [[UIApplication sharedApplication]delegate];
[appDelegate makeSplitViewController];
}
It would be great if someone could point out where I am going wrong. I have been stuck with this problem for quite a few days and I have tried everything that comes to my mind...
UIWindow has a subview that it uses for rotations and puts other views inside of that. You need to insert yourself into the root view (or something lower), not the window. Look at -[UIWindow rootViewController].
UIView *rootView = [[[self window] rootViewController] view];
[rootView addSubview:view];
This will work as long as you're using something with a root view controller. This will work as long as rootViewController isn't nil. If you're doing a raw "View Based" application, then it's usually best to pick another view and add your view as its sibling rather than digging through the undocumented hierarchy:
UIView *sibling = ... (some other view)
[[sibling superview] addSubview:view];

Resources