Basically, I have a Table View Controller and a normal View Controller, I want to make it so that I can swipe between the view controllers like on the home screen of app (obvious same type of view controller).
But the thing I am finding is that the UIpageviewcontroller is usaully used when you have multiple views of the same type of viewcontroller for example swiping between pictures, you could just set an index in the class and an array of images relating to the index and set it up that way.
But I'm trying to get different view controllers in this set up. Right now it's two but will definitely go up to about 4.
Is UIPageViewController the right way to set it up or something else.
EDIT: Code added below
//
// ViewController.m
// testb
//
#import "MainPostController.h"
#import "MainTableViewController.h"
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize pageViewController;
#synthesize indexValue = _indexValue;
- (void)viewDidLoad
{
[super viewDidLoad];
self.indexValue= 1;
NSLog(#"main intitated");
// Do any additional setup after loading the view, typically from a nib.
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageViewController"];
self.pageViewController.dataSource = self;
MainTableViewController *tvc = [self.storyboard instantiateViewControllerWithIdentifier:#"MainTableViewController"];
MainPostController *pvc;
NSArray *viewcontrollers =[NSArray arrayWithObjects:tvc, pvc, nil];
[self.pageViewController setViewControllers:viewcontrollers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
self.pageViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 30);
[self addChildViewController:pageViewController];
[self.view addSubview:pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
if (self.indexValue == 1) {
MainPostController *pvc = [self.storyboard instantiateViewControllerWithIdentifier:#"MainPostController"];
self.indexValue = 0 ;
return pvc;
}
else return nil;
}
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
if (self.indexValue == 0) {
MainTableViewController *tvc = [self.storyboard instantiateViewControllerWithIdentifier:#"MainTableViewController"];
self.indexValue = 1;
return tvc;
}
else return nil;
}
#end
I want the intial view to be the table view controller(tvc) and i want the Post view controller(pvc) to be to its left. I can load it up and swipe between the two easily but sometime i can swipe further than the boundaries so basically if i start on the tvc-->pvc-->tvc then i can go further by swiping right to the same tvc then the boundary is reached or go the other way tvc-->pvc-->tvc-->pvc-->pvc by swiping left for the last transition. The boundaries are reached in the end. Once the app intially launches at tvc i cannot go forward a page, (which is what should happen) and if i go tvc-->pvc and try to go to a page to the left it wont let me (which is what should happen)
Thanks
Finally done it, didn't have to add any properties to the different classes. Just tested the class. Heres the code:
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
if ([viewController isKindOfClass:[MainTableViewController class]]) {
MainPostController *pvc = [self.storyboard instantiateViewControllerWithIdentifier:#"MainPostController"];
return pvc;
}
else return nil;
}
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
if ([viewController isKindOfClass:[MainPostController class]]) {
MainTableViewController *tvc = [self.storyboard instantiateViewControllerWithIdentifier:#"MainTableViewController"];
return tvc;
}
else return nil;
}
Should be easy to add more view controllers as i just need to add else if statements to test them. The main problem solver was the method isKindOfClass:
Thanks for your reply guys!
I had the same issue, here's what i did and working perfectly.
.h
#interface ViewController : UIViewController <UIPageViewControllerDataSource>
#property (strong, nonatomic) UIPageViewController *pageViewController;
#property (nonatomic) NSArray *viewControllerIDArr;
#end
.m
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self setupDefaults];
}
- (void)setupDefaults
{
self.viewControllerIDArr = #[#"FirstViewController", #"SecondViewController"];
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageViewController"];
self.pageViewController.dataSource = self;
UIViewController *startingViewController = [self.storyboard instantiateViewControllerWithIdentifier:self.viewControllerIDArr[0]];
NSArray *viewControllers = #[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
self.pageViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 45);
[self addChildViewController:_pageViewController];
[self.view addSubview:_pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
}
- (UIViewController *)getViewControllerFromClass:(Class)class isNext:(BOOL)next
{
NSInteger index = [self.viewControllerIDArr indexOfObject:[NSString stringWithFormat:#"%#", class]];
if (next)
index+=1;
else
index-=1;
if (index < 0 || index >= self.viewControllerIDArr.count)
return nil;
else
return [self.storyboard instantiateViewControllerWithIdentifier:self.viewControllerIDArr[index]];
}
#pragma mark - Page View Controller Data Source
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
return [self getViewControllerFromClass:viewController.class isNext:NO];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
return [self getViewControllerFromClass:viewController.class isNext:YES];
}
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
{
return 0;
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
{
return 0;
}
Note:
self.viewControllerIDArr containers Storyboard ID's of the viewControllers.
It looks like this in storyboard:
This is an old question but since I bumped into this problem I'll post my solution.
The first time I did this I added my code
func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { }
Which received problems when you continuously scroll the views using two fingers and didFinishAnimating is not called unless scrolling stops.
So I just used this delegate method instead.
func pageViewController(pageViewController: UIPageViewController, willTransitionToViewControllers pendingViewControllers: [UIViewController]) {
let currentView = pendingViewControllers[0]
if currentView is UINavigationController && currentView.restorationIdentifier == "Settings" {
index = 0
} else if currentView is UINavigationController && currentView.restorationIdentifier == "Main" {
index = 1
} else if currentView is UINavigationController && currentView.restorationIdentifier == "Message" {
index = 2
}
}
Where currentView is the currentUIViewController (or UINavigationController like what I am using, using a restorationIdentifier to identify my navigation controller as well), and index is a global value to know which UIViewController in the array to instantiate.
You could use a UIViewPageViewController, with some custom logic.
As you say, the normal way to handle this is to have the page view controller's data source simply create the same type of view controller for each page and fill it with data from your model.
In your case, you could add a pageNumber property to all the view controllers that you're going to host in your page view controller. Then, in the data source methods, use the page number of the old view controller to figure out the new page number. Then have a switch statement based on page number. Each case in the switch statement would create a different type of view controller.
Related
I have an UIPageViewController. I can flip the pages and everything works fine. The UIPageViewController pre-loads one ViewController. At this point, there are two view controllers in memory (one is the visible controller while another is the pre-loaded controller). I want to get the two ViewControllers so that I could change some settings on the fly.
The question is how could I get the pre-loaded child view controllers? If I cannot get those controllers, what is the best way to reset some properties on all the preloaded view controllers?
You can modify your custom object which can be used to build your view controller:
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
NSUInteger index = [(PageChildViewController *) viewController index];
if (index == 0) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)viewControllerAtIndex:(NSUInteger)index {
CustomObject *customObject = self.customObjects[index];
PageChildViewController *childViewController = [PageChildViewController controllerWithIndex:index andCustomObject:customObject];
return childViewController;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
NSUInteger index = [(PageChildViewController *) viewController index];
index++;
if (index == self.pages.count) {
return nil;
}
return [self viewControllerAtIndex:index];
}
If you need to update currently visible page view controller you can use this:
[self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
If you need to reset you page view controller cache you can use this:
self.pageController.dataSource = nil;
self.pageController.dataSource = self;
I want to jump between two UIViewcontrollers
through swipe action.
Currently, I implemented a UIScrollView, and added UIViewcontrollers(vc1 and vc2) on it, so
On vc1
swipe left : jump to vc2
swipe right : do nothing
On vc2
swipe left : do nothing
swipe right : jump to vc1
But what I want is:
On vc1
swipe left : jump to vc2
swipe right : jump to vc2
On vc2
swipe left : jump to vc1
swipe right : jump to vc1
So, how to achieve?
Try this
Steps:
In your view controller Create a UIPageViewController
self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
Add your both view controller on UIPageViewController
NSArray *viewControllers = //add your two view controllers in array;
[self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
Set data source and Add UIPageViewController as child view controller
self.pageController.dataSource = self;
[self addChildViewController:self.pageController];
Now, You need to implement two methods
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
NSUInteger index = [(ViewController *)viewController index];
if (index == 0) {
return nil;
}
// Decrease the index by 1 to return
index--;
return viewControllers[index];//[self viewControllerAtIndex:index];//viewControllerAtIndex
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
NSUInteger index = [(ViewController *)viewController index];
if (index == 1) {
return nil;
}
index++;
return viewControllers[index];
}
I have implemented a UIPageViewController that I want to be able to scroll infinitely to the right (as in the user swipes to the left) and be able to scroll backwards in the other direction all the way to the start. However I don''t want the user to be able to scroll left (as in the user swipe to the right) on the very first page, even though I only have three pages that loop, how can I do this?
I have already figured out how to make an infinite scroll with three view controllers to the right ( as in user scrolls to the left) but when the user tries to scroll to the left (as in user swipes to the right) it bugs out and the screen goes white?
Can anyone improve on this code so the user can infinitely scroll both ways, not just one? and if possible prevent the user from scrolling backwards on the very first panel? thanks.
PageViewController.h
#import <UIKit/UIKit.h>
#interface PageViewController : UIPageViewController
<UIPageViewControllerDelegate, UIPageViewControllerDataSource>
#end
PageViewController.m
#import "PageViewController.h"
#interface PageViewController ()
#end
#implementation PageViewController
{
NSArray *myViewControllers;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.delegate = self;
self.dataSource = self;
UIViewController *p1 = [self.storyboard
instantiateViewControllerWithIdentifier:#"ContentViewController1"];
UIViewController *p2 = [self.storyboard
instantiateViewControllerWithIdentifier:#"ContentViewController2"];
UIViewController *p3 = [self.storyboard
instantiateViewControllerWithIdentifier:#"ContentViewController3"];
myViewControllers = #[p1,p2,p3];
[self setViewControllers:#[p1]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO completion:nil];
NSLog(#"loaded!");
}
-(UIViewController *)viewControllerAtIndex:(NSUInteger)index
{
return myViewControllers[index];
}
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger currentIndex = [myViewControllers indexOfObject:viewController];
--currentIndex;
currentIndex = currentIndex % (myViewControllers.count);
return [myViewControllers objectAtIndex:currentIndex];
}
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger currentIndex = [myViewControllers indexOfObject:viewController];
++currentIndex;
currentIndex = currentIndex % (myViewControllers.count);
return [myViewControllers objectAtIndex:currentIndex];
}
-(NSInteger)presentationCountForPageViewController:
(UIPageViewController *)pageViewController
{
return myViewControllers.count;
}
-(NSInteger)presentationIndexForPageViewController:
(UIPageViewController *)pageViewController
{
return 0;
}
#end
You can use Flag to know the initial View (first view).then use this scroll enable and disable method to prevent the swipe.
-(void)setScrollEnabled:(BOOL)enabled forPageViewController:(UIPageViewController*)pageViewController{
for(UIView* view in pageViewController.view.subviews){
if([view isKindOfClass:[UIScrollView class]]){
UIScrollView* scrollView=(UIScrollView*)view;
[scrollView setScrollEnabled:enabled];
return;
}
}
Hope this Will Work.
I am using a separate .h, .m, and .xib files for each UIViewController based page of a UIPageViewController based picture book. Each page is loaded with animations, music, etc. and takes about 4MB of memory. In Instruments, the free memory drops down about 4MB as each page is loaded. This memory is never released as the pages are turned. It eventually gives memory warnings. UIPageViewController seems to keep each page it instantiates in memory and won't unload it. So when pages are turned fast, the app crashes.
I would like to be able to unload all pages except the 3 needed by UIPageViewController - the previous, current, and next pages. How can I unload undesired pages since they were instantiated by UIPageViewController.
Below is the Array of the pages that UIPageViewController pulls from. All of the pages (Page1, Page2, etc.) basically just load image files, provide basic animation, and have music.
//ARRAY OF PAGES
pageArray = [[NSArray alloc] initWithObjects:
(id)[[Page1 alloc] initWithNibName:nil bundle:nil],
[[Page2 alloc] initWithNibName:nil bundle:nil],
[[Page3 alloc] initWithNibName:nil bundle:nil],
[[Page4 alloc] initWithNibName:nil bundle:nil],
[[Page5 alloc] initWithNibName:nil bundle:nil],
[[Page6 alloc] initWithNibName:nil bundle:nil],
[[Page7 alloc] initWithNibName:nil bundle:nil],
[[Page8 alloc] initWithNibName:nil bundle:nil],
// continues all the way up to page 47
[[Page47 alloc] initWithNibName:nil bundle:nil],
nil];
I've left out the standard initialization for UIPageViewController. It uses "nextPageNumber" to pull the right page from the pageArray above to create a new page object.
-(void)turnPageForward{
[pageController setViewControllers:[NSArray arrayWithObject:[pageArray objectAtIndex:nextPageNumber]]
direction:UIPageViewControllerNavigationDirectionForward
animated:YES completion:^(BOOL finished){
}];
}
I have tried creating an object "pageIndex" (see below) that is set to nil after providing it to the pageController. It didn't work. The page still took up memory well after the pages had advanced.
//PROGRAM PAGE FORWARD
-(void)turnPageForward{
UIViewController * pageIndex =[pageArray objectAtIndex:nextPageNumber]; //nextPageNumber is the next page to load
[pageController setViewControllers:[NSArray arrayWithObject:pageIndex]
direction:UIPageViewControllerNavigationDirectionForward
animated:YES completion:^(BOOL finished){
}];
pageIndex = nil;
}
I've looked through stackoverflow for posts using the same way of supplying pages to UIPageViewController, but haven't found anything close. The closest was "ARC not releasing memory when going “back” in navigation controller" but doesn't set the view controllers the same way.
I've tried to set the undesired pages to nil so ARC can remove them with no luck. Any suggestions or alternate paths I should try? I like the page curl effect and have not been able to find a good one elsewhere that does horizontal page curls.
Thanks! Eric
"UIPageViewController seems to keep each page it instantiates in memory"
No, you're doing that by instantiating all those "pages" (controllers), and putting them into an array (the memory jumps as you turn the page because the controller's view is not actually loaded until you display it, even though the controller has been instantiated. But once you've done that, your controller retains its view and the array retains the controller). You just need to keep some kind of count of which page you're on, and in the implementation of viewControllerBeforeViewController: and viewControllerAfterViewController:, instantiate a page there. When you go away from that page, its controller will be dealloc'd. If the loading is slow, you might need to keep an array that has the current page and the ones before and after -- UIPageViewController does do that if you have it set to scroll instead of page curl for the transition.
I made a simple test app like this:
#implementation ViewController {
int count;
}
- (void)viewDidLoad
{
[super viewDidLoad];
count = 1;
self.pager = [[UIPageViewController alloc]initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationDirectionForward options:nil];
self.pager.dataSource = self;
self.pager.delegate = self;
Page1 *first = [[Page1 alloc] initWithNibName:#"Page1" bundle:nil];
[self.pager setViewControllers:#[first] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
[self addChildViewController:self.pager];
[self.view addSubview:self.pager.view];
[self.pager didMoveToParentViewController:self];
}
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
if (count > 1) {
NSString *nibName = [#"Page" stringByAppendingFormat:#"%d",count-1];
UIViewController *prev = [[NSClassFromString(nibName) alloc] initWithNibName:nibName bundle:nil];
count -= 1;
return prev;
}
return nil;
}
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
if (count < 3) {
NSString *nibName = [#"Page" stringByAppendingFormat:#"%d",count+1];
UIViewController *next = [[NSClassFromString(nibName) alloc] initWithNibName:nibName bundle:nil];
count += 1;
return next;
}
return nil;
}
My example only has 3 pages, but it illustrates one way to do this. I put logs in the dealloc methods of the 3 controllers, and they were called when I navigated away from them.
I know this question is a bit older, but maybe my approach can help some people facing the same issue when not using ARC.
I think the best way to release unused pages is in the didFinishAnimation method of the UIPageViewController. You get the 1 or 2 previous view controllers there and you can easily release them. I do it like this:
-(void)pageViewController:(UIPageViewController *)thePageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {
if(completed) {
for (UIViewController *viewController in previousViewControllers) {
[viewController release];
}
}
}
It is important that you only release them if the action was completed because otherwise with the next page change you would try to access released pages.
Hope this helps!
I encounter this problem this time.
And after an hour thinking,I had find a solution.
This is my .h file
#import <UIKit/UIKit.h>
#interface BKContentViewController : UIPageViewController
#end
And my .m file and viewDidload method
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.delegate = self;
self.dataSource = self;
[self setViewControllers:[NSArray arrayWithObject:detailContent]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:NULL];
}
And the most important.
#pragma mark - UIPageViewControllerDataSource UIPageViewControllerDelegate
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed{
if (completed) {
[self setViewControllers:[NSArray arrayWithObject:detailContent]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:NULL];
}
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerAfterViewController:(UIViewController *)viewController{
if (!detailRight) {
detailRight = [[DetailContent alloc] init];
[detailRight setShouldReturn:YES];
[detailRight setPath:fPath withFileName:fName];
}
return detailRight;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerBeforeViewController:(UIViewController *)viewController{
if (!detailLeft) {
detailLeft = [[DetailContent alloc] init];
[detailLeft setShouldReturn:YES];
[detailLeft setPath:fPath withFileName:fName];
}
return detailLeft;
}
- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController
spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation{
UIViewController *currentViewController = [self.viewControllers objectAtIndex:0];
NSArray *viewControllers = [NSArray arrayWithObject:currentViewController];
[self setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];
self.doubleSided = NO;
return UIPageViewControllerSpineLocationMin;
}
After this, I have only three viewContrller and the memory will not increase by scroll again and again.
Hope this will help you.
I may have some misunderstanding regarding the use of the UINavigationControllerDelegate protocol. Here is my situation:
I have a ViewController, let's call it, BViewController that may display a PopoverViewController. BViewController is the second ViewController in a NavigationContoller's stack, after AViewController. I need to dismiss the PopoverViewController when the user hits a button in BViewController and the app takes us back to the previous view--AViewController.
To do that, I have implemented the following in BViewController
- (void)viewWillDisappear:(BOOL)animated {
NSLog(#"BViewController will disappear");
// Check whether the popoverViewController is visible
if (self.popoverController.popoverVisible==YES) {
[self.popoverController dismissPopoverAnimated:NO];
}
}
However, that is not being called directly by the framework as BViewController is inside a NavigationController. Hence, I register a UINavigationControllerDelegate with my NavigationController and implement the following two methods:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
// Pass the message on to the viewController in question
[viewController viewWillAppear:animated];
}
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
// Pass the message on to the viewController in question
[viewController viewWillDisappear:animated];
}
However, it seems that the passed in viewController parameter in both methods is the one that is about to be shown. I would have expected that the second method gives me access to the one that is about to disappear. So, when the user hits aforementioned button viewWillDisappear gets called on AViewController (which is about to be shown) and not on BViewController (which is about to disappear). Does that sound right? The apple documentation refers in both cases to
The view controller whose view and navigation item properties are being shown.
...which is not quite clear, I think. Thank you for some help, guys.
The two delegate method are both called for the same action (showing a view controller). The navigationController: willShowViewController:animated: is called before the new view controller is visible in the gui. The navigationController:navigationController didShowViewController:animated: is called after the new view controller is shown.
You will find this pattern in a lot of delegate protocols from apple. Unfortunately you do not have a delegate method in the NavigationViewController which tells you if the action was a pop or push.
I hook in my own protocol, which will know about the TO and FROM sides:
NavigationControllerDelegate.h:
#protocol NavigationControllerDelegate <NSObject>
#required
-(void) navigationController: (UINavigationController*) navController
willMoveFromViewController: (UIViewController*) from
toViewController: (UIViewController*) to;
#end
Instead of the regular UINavigationViewController, I then use a little helper class which keeps track of the view controllers:
NavigationHandler.h:
#interface NavigationHandler : NSObject <UINavigationControllerDelegate> {
NSMutableArray* m_viewControllers;
}
In my app delegate, I create one of these objects and set it as the delegate of the navigation controller:
...
m_navigationHandler = [[NavigationHandler alloc] init];
navigationController = [[UINavigationController alloc] initWithRootViewController: mainMenuViewController];
navigationController.delegate = m_navigationHandler;
...
And from then on its a simple case of comparing my own list of view controllers with what the navigation controller has:
NavigationHandler.m
#import "NavigationHandler.h"
#import "NavigationControllerDelegate.h"
#implementation NavigationHandler
-(id) init {
if ((self = [super init])) {
m_viewControllers = [[NSMutableArray alloc] init];
}
return self;
}
-(void) dealloc {
[m_viewControllers release];
[super dealloc];
}
- (void)navigationController:(UINavigationController *)navController
willShowViewController:(UIViewController *)viewController
animated:(BOOL)animated {
// Find out which viewControllers are disappearing and appearing
UIViewController* appearingViewController = nil;
UIViewController* disappearingViewController = nil;
if ([m_viewControllers count] < [navController.viewControllers count]) {
// pushing
if ([m_viewControllers count] > 0) {
disappearingViewController = [m_viewControllers lastObject];
}
appearingViewController = viewController;
[m_viewControllers addObject: viewController];
} else if ([m_viewControllers count] > [navController.viewControllers count]) {
// popping
disappearingViewController = [m_viewControllers lastObject];
appearingViewController = viewController;
[m_viewControllers removeLastObject];
} else {
return;
}
// Tell the view that will disappear
if (disappearingViewController != nil) {
if ([disappearingViewController conformsToProtocol: #protocol(NavigationControllerDelegate)]) {
if ([disappearingViewController respondsToSelector: #selector(navigationController:willMoveFromViewController:toViewController:)]) {
UIViewController<NavigationControllerDelegate>* vcDelegate = (UIViewController<NavigationControllerDelegate>*)disappearingViewController;
[vcDelegate navigationController: navController willMoveFromViewController: disappearingViewController toViewController: appearingViewController];
}
}
}
// Tell the view that will appear
if ([appearingViewController conformsToProtocol: #protocol(NavigationControllerDelegate)]) {
if ([appearingViewController respondsToSelector:#selector(navigationController:willMoveFromViewController:toViewController:)]) {
UIViewController<NavigationControllerDelegate>* vcDelegate = (UIViewController<NavigationControllerDelegate>*)appearingViewController;
[vcDelegate navigationController: navController willMoveFromViewController: disappearingViewController toViewController: appearingViewController];
}
}
}
#end