I am using the Storyboard, then in my AppDelegate has no navigation controller programming on hand (all normal so far).
Now i need to fire the "applicationDidEnterBackground" I would like my app point to the navigation controller to the first screen (ie) popToView or popToRoot.
I tried to use some means found as:
EDITED: - Insert the applicationDidEnterBackgoround Method
//*-- BEGIN
- (void)applicationDidEnterBackground:(UIApplication *)application
{
_mainMenuDelegate = [[UIStoryboard storyboardWithName: stb_name bundle: nil] instantiateViewControllerWithIdentifier: # "idMainMenu"];
[[_window.rootViewController navigationController] popToViewController: _mainMenuDelegate animated: NO];
OR
NSArray * = viewContrlls _window.subviews;
for (int i = 0; i <[viewContrlls count], i + +)
{
id obj = [viewContrlls objectAtIndex: i];
if ([obj isKindOfClass: [MainMenu class]])
{
[[_window.rootViewController navigationController] popToViewController: obj animated: YES];
return;
}
}
} //*-- END
But the first does not fire and, the second is just 1 result row and it is not the MainMenu, so do not jump to the ViewController.
My question is: How to do it, knowing that I am using Storyboard?
Thank you
Try that:
NSArray* viewControllers = [[_window.rootViewController navigationController] viewControllers];
for (int i = 0; i < [viewControllers count]; i++)
{
id obj = [viewControllers objectAtIndex: i];
if ([obj isKindOfClass: [MainMenu class]])
{
[[_window.rootViewController navigationController] popToViewController: obj
animated: YES];
return;
}
}
Hope it helps you.
Related
I have 3 page - A ViewController, B ViewController and C ViewController.
And A PageViewController control there horizontal scroll.
PagesViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
self.aVC = [self.storyboard
instantiateViewControllerWithIdentifier:#"AViewController"];
self.bVC = [self.storyboard
instantiateViewControllerWithIdentifier:#"BViewController"];
self.cVC = [self.storyboard
instantiateViewControllerWithIdentifier:#"CViewController"];
self.delegate = self;
self.dataSource = self;
self.allViewControllers = #[self.aVC,self.bVC
,self.cVC];
[self setViewControllers:#[self.aVC]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO completion:nil];
_pageControl = [UIPageControl appearance];
}
I want to change the _pageControl color when I scroll to A VC , B VC and C VC.
So I put the code in
-(NSInteger)presentationIndexForPageViewController:
(UIPageViewController *)pageViewController
{
NSLog(#"%#",pageViewController.viewControllers[0]);
for( int i = 0 ; i< self.allViewControllers.count ; i++ )
{
if( pageViewController.viewControllers[0] == self.allViewControllers[i])
{
if( i ==0 )
{
_pageControl.backgroundColor = [UIColor greenColor];
}
else if( i ==1)
{
_pageControl.backgroundColor = [UIColor redColor];
}
else
{
_pageControl.backgroundColor = [UIColor clearColor];
}
NSLog(#"return index:%d", i);
return i;
}
}
return 0;
}
But the page control was not change the color.
I try to put below the code in the viewDidLoad, it will change color at all the view controller.
_pageControl.backgroundColor = [UIColor redColor];
But now I want to change the pageControl color when I scroll to different UIViewController.
How can I do? or How can I refresh the pageControl color?
Because now the color always black.
I offer others delegate method about the PageViewController:
-(UIViewController*) pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger currentIndex = [self.allViewControllers indexOfObject:viewController];
if( currentIndex == 0 )
{
return nil;
}
currentIndex--;
return [self.allViewControllers objectAtIndex:currentIndex];
}
-(UIViewController *) pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger currentIndex = [self.allViewControllers indexOfObject:viewController];
NSLog(#"after currentIndex:%ld",currentIndex);
currentIndex++;
if( currentIndex == [self.allViewControllers count])
{
return nil;
}
return [self.allViewControllers objectAtIndex:currentIndex];
}
-(NSInteger)presentationCountForPageViewController:
(UIPageViewController *)pageViewController
{
return self.allViewControllers.count;
}
In your viewDidLoad: method,
instead of:
_pageControl = [UIPageControl appearance];
use:
NSArray *subviews = self.view.subviews;
_pageControl = nil;
for (int i=0; i<[subviews count]; i++) {
if ([[subviews objectAtIndex:i] isKindOfClass:[UIPageControl class]]) {
_pageControl = (UIPageControl *)[subviews objectAtIndex:i];
}
}
=====
EDIT:
For your specific project, you're not getting the _pageControl (it's returning nil) because the Storyboard has not completed instantiating your view controller in the viewDidLoad. I thought it would need to go in viewDidAppear:animated, but that didn't work either, so I cheated by delaying requesting it for 0.2 milliseconds.
In your viewDidLoad, put this:
[self performSelector:#selector(findPageControl) withObject:nil afterDelay:0.2f];
Then, add this method:
- (void) findPageControl {
NSArray *subviews = self.view.subviews;
_pageControl = nil;
for (int i=0; i<[subviews count]; i++) {
if ([[subviews objectAtIndex:i] isKindOfClass:[UIPageControl class]]) {
_pageControl = (UIPageControl *)[subviews objectAtIndex:i];
}
}
[self changePage:0];
}
In your viewControllerAfterViewController method, I added this right after the NSUInteger currentIndex = line:
[self changePage:currentIndex];
That seems to have made it work. Now, you could add an animation in your changePage method to make the transition seem a little smoother.
Also, when debugging, this is what I did:
I added a breakpoint on the _pageControl = line, so I could check and see what was happening. When I saw it was nil, that told me that it wasn't being set properly. Look in the debug area, and you can see what I printed out ("po") to see what values existed -- and why there was no UIPageControl. If you do the same after the changes I list above, you'll see that this is now found and set.
Here's an example, just with a pageControl in a UIViewController:
#import "ViewController.h"
#interface ViewController () {
UIPageControl *pageControl;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor lightGrayColor];
pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(10, 10, 100, 40)];
pageControl.numberOfPages = 6;
[pageControl addTarget:self action:#selector(changePage:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:pageControl];
}
- (void) changePage:(UIPageControl *)page {
NSInteger currentPage = page.currentPage;
switch (currentPage) {
case 0:
pageControl.backgroundColor = [UIColor redColor];
break;
case 1:
pageControl.backgroundColor = [UIColor greenColor];
break;
case 2:
pageControl.backgroundColor = [UIColor blueColor];
break;
default:
break;
}
}
#end
I have 4 tabs and all have UIWebView. I want that the first tab should load and displayed immediately without waiting for others to load. For which I did this in UITabBarController class:
for(UIViewController * viewController in self.viewControllers){
if(![[NSUserDefaults standardUserDefaults]boolForKey:#"isSessionExpired"])
{
if((int)[self.viewControllers indexOfObject:viewController] != 4)
{
viewController.tabBarItem.tag = (int)[[self viewControllers] indexOfObject:viewController];
[viewController view];
}
}
}
But the main thread waits for all tabs to load.
I tried this with GCD using dispatch_async
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ // 1
dispatch_async(dispatch_get_main_queue(), ^{
UIViewController *firstContrl = [self.viewControllers objectAtIndex:0];
firstContrl.tabBarItem.tag = (int)[[self viewControllers] indexOfObject:firstContrl];
[firstContrl view];
dispatch_async(dispatch_get_main_queue(), ^{ // 2
UIViewController *secContrl = [self.viewControllers objectAtIndex:1];
secContrl.tabBarItem.tag = (int)[[self viewControllers] indexOfObject:secContrl];
[secContrl view];
dispatch_async(dispatch_get_main_queue(), ^{ // 3
UIViewController *thirdContrl = [self.viewControllers objectAtIndex:2];
thirdContrl.tabBarItem.tag = (int)[[self viewControllers] indexOfObject:thirdContrl];
[thirdContrl view];
dispatch_async(dispatch_get_main_queue(), ^{ // 4
UIViewController *fourthContrl = [self.viewControllers objectAtIndex:3];
fourthContrl.tabBarItem.tag = (int)[[self viewControllers] indexOfObject:fourthContrl];
[fourthContrl view];
});
});
});
});
});
But this doesn't work either. It takes the same time to display the first tab.
How can this be fixed?
Ehm.. GCD and UIWebView's -loadRequest: doesn't work as you think. All the code above is pretty equal to:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
UIViewController *firstContrl = [self.viewControllers objectAtIndex:0];
firstContrl.tabBarItem.tag = (int)[[self viewControllers] indexOfObject:firstContrl];
[firstContrl view];
UIViewController *secContrl = [self.viewControllers objectAtIndex:1];
secContrl.tabBarItem.tag = (int)[[self viewControllers] indexOfObject:secContrl];
[secContrl view];
UIViewController *thirdContrl = [self.viewControllers objectAtIndex:2];
thirdContrl.tabBarItem.tag = (int)[[self viewControllers] indexOfObject:thirdContrl];
[thirdContrl view];
UIViewController *fourthContrl = [self.viewControllers objectAtIndex:3];
fourthContrl.tabBarItem.tag = (int)[[self viewControllers] indexOfObject:fourthContrl];
[fourthContrl view];
});
});
To solve your problem you need to implement queue depends on - (void)webViewDidFinishLoad:(UIWebView *)webView. The idea is:
First view controller's webView starts loading request
asynchronously;
When request is loaded (or failed), webView will notify your
delegate;
Notify all other view controllers with webView, to let them start
loading their requests;
If I were you, I would implement it in next way:
// FirstViewController.h
extern NSString * const FirstViewControllerDidLoadWebView;
// FirstViewController.m
NSString * const FirstViewControllerDidLoadWebView=#"FirstViewControllerDidLoadWebView";
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
// notify other controllers, to let them load their web views:
[[NSNotificationCenter defaultCenter] postNotificationName:FirstViewControllerDidLoadWebView
object:nil];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
// loading failed. Try to load it few more times but anyway notify other controllers after:
[[NSNotificationCenter defaultCenter] postNotificationName:FirstViewControllerDidLoadWebView
object:nil];
}
After that, 'subscribe' all other(only tabs) view controllers for FirstViewControllerDidLoadWebView notification and load their WebView after it arrives.
For more details check NSNotificationCenter and UIWebViewDelegate
I am loading multiple UIViewControllers in UIPageViewController with each UIViewController having their own navigation bar. I have implemented all the required data source and delegate methods for UIPageViewController and it showing up correctly.
But when I scroll my view controller horizontally, more often, I see a white blank screen instead of my view controller. Below is my code.
Any clue what could be wrong here.
PS: I tried by removing the IF condition in my viewControllerForRequestID method and returning a new controller every time. This works but then I end up with one view controller showing up twice in pagination.
- (UIViewController *)pageViewController:(UIPageViewController *)iPageViewController viewControllerBeforeViewController:(UIViewController *)iViewController {
[self.pageControl setCurrentPage:self.selectedRequestIndex];
if (self.selectedRequestIndex == 0) {
return nil;
}
NSUInteger aNewSelectedRequestIndex = self.selectedRequestIndex - 1;
NSString *aPreviousRequestID = [self.paginationRequestIDList[aNewSelectedRequestIndex] stringValue];
self.selectedRequestIndex = aNewSelectedRequestIndex;
self.selectedRequestID = aPreviousRequestID;
return [self viewControllerForRequestID:self.selectedRequestID];
}
- (UIViewController *)pageViewController:(UIPageViewController *)iPageViewController viewControllerAfterViewController:(UIViewController *)iViewController {
[self.pageControl setCurrentPage:self.selectedRequestIndex];
if (self.selectedRequestIndex == NSNotFound || self.selectedRequestIndex >= self.paginationRequestIDList.count - 1) {
return nil;
}
NSUInteger aNewSelectedRequestIndex = self.selectedRequestIndex + 1;
NSString *aNextRequestID = self.paginationRequestIDList[aNewSelectedRequestIndex];
self.selectedRequestIndex = aNewSelectedRequestIndex;
self.selectedRequestID = aNextRequestID;
return [self viewControllerForRequestID:self.selectedRequestID];
}
- (MyNavigationViewController *)viewControllerForRequestID:(id)iRequestID {
NSString *aRequestID = iRequestID;
// Safe check to avoid numbers in request ID
if (![iRequestID isKindOfClass:[NSString class]]) {
aRequestID = [iRequestID stringValue];
}
#synchronized (self) {
if ([self.viewControllers containsObjectForKey:iRequestID]) {
MyNavigationViewController *aNavigationController = self.viewControllers[iRequestID];
return aNavigationController;
}
MyDataModel *aRequestData = self.savedRequestData[iRequestID];
MyDataModelController *aRequestInfoController = [[MyDataModelController alloc] initWithRequestData:aRequestData];
aRequestInfoController.delegate = self;
MyNavigationViewController *aNavigationController = [[MyNavigationViewController alloc] initWithRootViewController:aRequestInfoController];
[self.viewControllers setObject:aNavigationController forKey:iRequestID];
return aNavigationController;
}
}
I've been trying to use the UIPageViewController to display 3 different nibs for a few days on and off now and have almost got it working. I still have one weird bug that I cant figure out.
Basically the app starts, I can scroll between the 3 pages one after another with out any problems, eg:
Page1->Page2->Page3
and then back to the start:
Page3->Page2->Page1.
No Problems. The issue is that if I scroll, for example from Page3->Page2, then BACK to Page3, Page3 Dissappears when it snaps into place. If I scroll to where a forth page would be, then I get Page3. Here is the code relevant to the UIPageViewController, the nibs and the delegate methods for the UIPageViewController:
- (void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageViewController.delegate = self;
[[self.pageViewController view] setFrame:[[self view] bounds]];
indexTest = 0;
Page1 *p1 = [[Page1 alloc]initWithNibName:#"Page1" bundle:nil];
p1.view.tag = 1;
Page2 *p2 = [[Page2 alloc]initWithNibName:#"Page2" bundle:nil];
p2.view.tag = 2;
Page3 *p3 = [[Page3 alloc]initWithNibName:#"Page3" bundle:nil];
p3.view.tag = 3;
NSArray *arr = [[NSArray alloc] initWithObjects:p1,nil];
viewControllers = [[NSMutableArray alloc] initWithObjects:p1,p2,p3, nil];
[self.pageViewController setViewControllers:arr direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
self.pageViewController.dataSource = self;
[self addChildViewController:self.pageViewController];
[[self view] addSubview:[self.pageViewController view]];
[self.pageViewController didMoveToParentViewController:self];
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
}
#pragma mark - page view controller stuff
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
if (indexTest > 0) {
switch (indexTest) {
case 1:{
NSLog(#"NO page is BEFORE current page");
break;
}
case 2:{
NSLog(#"Page BEFORE is Page: %#", [NSString stringWithFormat:#"%#",[viewControllers objectAtIndex:0] ] );
indexTest--;
return [viewControllers objectAtIndex:0];
break;
}
default:{
NSLog(#"PROBLEM in viewBEFORE, indexTest = %d!!!!", indexTest);
break;
}
}
}
return nil;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
if (indexTest < NUM_OF_PAGES) {
switch (indexTest) {
case 0:{
NSLog(#"Page AFTER is Page: %#", [NSString stringWithFormat:#"%#",[viewControllers objectAtIndex:1] ] );
indexTest++;
return [viewControllers objectAtIndex:1];
break;
}
case 1:{
NSLog(#"Page AFTER is Page: %#", [NSString stringWithFormat:#"%#",[viewControllers objectAtIndex:2] ] );
indexTest++;
return [viewControllers objectAtIndex:2];
break;
}
case 2:{
NSLog(#"No pages AFTER this current page %d", indexTest);
break;
}
default:{
NSLog(#"PROBLEM in viewAFTER, indexTest = %d!!!!", indexTest);
break;
}
}
}
return nil;
}
Finally the page index dots code
#pragma mark - dot controller
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController {
// The number of items reflected in the page indicator.
return NUM_OF_PAGES;
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController {
// The selected item reflected in the page indicator.
return 0;
}
Any and all help is much appreciated, I think I'm just doing something silly that I cant see as I'm so close to it fully working. If anythings not clear or I haven't give enough information please let me know and I'll answer it as best as I can.
Thanks
I think your indexTest logic is wrong, it's showing the wrong indexes for the viewControllers. I wouldn't use those methods to keep track of the index as they can be called even when the views aren't actually going to change.
Instead you could replace the selection of view controllers like this:
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
int vcIndex = [self.viewControllers indexOfObject:viewController];
if (vcIndex > 0) {
return [self.viewControllers objectAtIndex:vcIndex-1];
}
return nil;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
int vcIndex = [self.viewControllers indexOfObject:viewController];
if (vcIndex < NUM_OF_PAGES-1) {
return [self.viewControllers objectAtIndex:vcIndex+1];
}
return nil;
}
And if you need to keep track of the current index, use the delegate method provided.
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {
if (completed && finished) {
UIViewController *currentVC = pageViewController.viewControllers[0];
indexTest = [self.viewControllers indexOfObject:currentVC];
}
}
Just note that if your using this method, don't call setViewControllers: amimated:YES as this will lose track of the correct position.
Side note: I too have been struggling with UIPageViewController and found it was quicker and easier to write my own version. I think it has too many bugs.
I m using UIPageViewController on iPad where I need to show a firstviewController in the first page and ContentViewController in the next page in landscape.
If I set the NSArray with two viewControllers the app is crashes at [self.pagviewController setViewController:] with the following exception:
The number of provided view controllers (2) doesn't match the number required (1) for the requested spine location (UIPageViewControllerSpineLocationMin)
Below is the code:
#pragma mark - UIPageViewControllerDataSource Methods
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger currentIndex = [self.modelArray indexOfObject:[(ContentViewController *)viewController textContents]];
if(currentIndex == 0)
{
return nil;
}
ContentViewController *contentViewController = [[ContentViewController alloc] init];
contentViewController.textContents = [self.modelArray objectAtIndex:currentIndex - 1];
return contentViewController;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger currentIndex = [self.modelArray indexOfObject:[(ContentViewController *)viewController textContents]];
if(currentIndex == self.modelArray.count-1)
{
return nil;
}
ContentViewController *contentViewController = [[ContentViewController alloc] init];
contentViewController.textContents = [self.modelArray objectAtIndex:currentIndex + 1];
return contentViewController;
}
//#pragma mark - UIPageViewControllerDelegate Methods
- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController
spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation
{
if(UIInterfaceOrientationIsPortrait(orientation))
{
//Set the array with only 1 view controller
UIViewController *currentViewController = [self.pageViewController.viewControllers objectAtIndex:0];
NSArray *viewControllers = [NSArray arrayWithObject:currentViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];
//Important- Set the doubleSided property to NO.
self.pageViewController.doubleSided = NO;
//Return the spine location
return UIPageViewControllerSpineLocationMin;
}
else
{
NSArray *viewControllers = nil;
ContentViewController *currentViewController = [self.pageViewController.viewControllers objectAtIndex:0];
NSUInteger currentIndex = [self.modelArray indexOfObject:[(ContentViewController *)currentViewController textContents]];
if(currentIndex == 0 || currentIndex %2 == 0)
{
UIViewController *nextViewController = [self pageViewController:self.pageViewController viewControllerAfterViewController:currentViewController];
viewControllers = [NSArray arrayWithObjects:currentViewController, nextViewController, nil];
}
else
{
UIViewController *previousViewController = [self pageViewController:self.pageViewController viewControllerBeforeViewController:currentViewController];
viewControllers = [NSArray arrayWithObjects:previousViewController, currentViewController, nil];
}
//Now, set the viewControllers property of UIPageViewController
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];
return UIPageViewControllerSpineLocationMid;
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
appDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
//Instantiate the model array
self.modelArray = [[NSMutableArray alloc] init];
self.vcs = [[NSMutableArray alloc]init];
for (int index = 1; index <= 2 ; index++)
{
[self.modelArray addObject:[NSString stringWithFormat:#"Page %d",index]];
}
//Step 1
//Instantiate the UIPageViewController.
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl
navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
//Step 2:
//Assign the delegate and datasource as self.
self.pageViewController.delegate = self;
self.pageViewController.dataSource = self;
//Step 3:
//Set the initial view controllers.
appDelegate.contentViewController.textContents = [self.modelArray objectAtIndex:0];
NSArray *viewControllers = [NSArray arrayWithObjects:appDelegate.firstViewController,appDelegate.contentViewController,nil];
[self.pageViewController setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
//Step 4:
//ViewController containment steps
//Add the pageViewController as the childViewController
[self addChildViewController:self.pageViewController];
//Add the view of the pageViewController to the current view
[self.view addSubview:self.pageViewController.view];
//Call didMoveToParentViewController: of the childViewController, the UIPageViewController instance in our case.
[self.pageViewController didMoveToParentViewController:self];
//Step 5:
// set the pageViewController's frame as an inset rect.
CGRect pageViewRect = self.view.bounds;
pageViewRect = CGRectInset(pageViewRect, 40.0, 40.0);
self.pageViewController.view.frame = pageViewRect;
//Step 6:
//Assign the gestureRecognizers property of our pageViewController to our view's gestureRecognizers property.
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
}
The problem is you passing an array containing two view controllers to the page view controller while it expects one at a time, change your array to be like this :
NSArray *viewControllers = #[appDelegate.firstViewController];
You will pass one of the views but viewControllerAfterViewController and viewControllerBeforeViewController will handle the rest.
Ah..Finally got solution for this same issue.., it may helps you..
When we set the spine location to UIPageViewControllerSpineLocationMid, the doubleSided property of the pageViewController is automatically set to YES. This means that the content on page front will not partially show through back. But when this property is set to NO, the content on page front will partially show through back, giving the page a translucent kind of effect. So, in the portrait orientation, we have to set the value to NO, otherwise it would result in an exception.
So in your UIPageviewcontroller delegate method, in else part add this doubleSided property as YES when you return spineLocation as UIPageViewControllerSpineLocationMid
self.pageViewController.doubleSided = YES;
return UIPageViewControllerSpineLocationMid;
self.pageViewController.doubleSided = NO;
return UIPageViewControllerSpineLocationMid;
This is the solution for the exception.
In xcode it self you could find this.
Go to the UIPageViewcontroller class there you could see the explanation for this like:
#property (nonatomic, readonly) UIPageViewControllerSpineLocation spineLocation; // If transition style is 'UIPageViewControllerTransitionStylePageCurl', default is 'UIPageViewControllerSpineLocationMin', otherwise 'UIPageViewControllerSpineLocationNone'.
// Whether client content appears on both sides of each page. If 'NO', content on page front will partially show through back.
// If 'UIPageViewControllerSpineLocationMid' is set, 'doubleSided' is set to 'YES'. Setting 'NO' when spine location is mid results in an exception.
#property (nonatomic, getter=isDoubleSided) BOOL doubleSided; // Default is 'NO'.
Instead of implementing a full data source, you can set the PageViewController with one view controller at a time each time the user pushes a next or back button, like
[pageViewController setViewControllers:#[contentViewController]
direction:UIPageViewControllerNavigationDirectionForward
animated:YES
completion:nil];
This will animate the page transition as you switch.