Pregunta

Please forgive me, there are already a ton of questions on how to add a UIBarButtonItem to a NavigationBar programmatically but I just can't seem to get any of the solutions to work in my situation.

Here is the layout of a simple test app I have been working with to learn the UIPageViewController.

storyboard

I have the page view controller working nicely with three unique viewControllers. I would now like to set unique rightBarButtonItems for each of the view controllers. I can easily set a common barButtonItem in the DetailViewController by simply doing this.

UIBarButtonItem *newButton = [[UIBarButtonItem alloc] initWithTitle:@"Whatever" 
                              style:UIBarButtonItemStylePlain 
                              target:self 
                              action:@selector(doSomething)];    

self.navigationItem.rightBarButtonItem = newButton;

Given that I need a unique button for each of the three pages in the pageViewController I am not able to set the button in the detailViewController. I have tried the code above in viewDidAppear of the three controllers but the buttons will not appear. I have also tried creating the button in the same way and then setting it like this with no luck.

DetailViewController *vc = [[DetailViewController alloc] init];
vc.navigationItem.rightBarButtonItem = newButton;

I know I'm close here, I'm just not sure how to specify I need to add a button to the NavigationBar of the NavigationController that is running the detailViewController that my contentViewControllers are embedded in. Any help would be great ESPECIALLY SNIPPETS.

As a side note I have tried a few other methods that have come up problematic.

  • Setting the button in viewDidLoad rather than viewDidAppear
    • This will not work because the viewDidLoad method is not called everytime you swipe from one page to the next. The viewDidAppear method is however so I am trying to set the button there. It is possible viewWillAppear is called everytime but I haven't checked.
  • Setting the button in the UIPageViewController delegate methods
    • This is problematic if the user flips through the pages to quickly the button will fail to change or fail to appear.

SOLUTION

It turns out I was close… Rather than creating the button in the UIPageViewController methods I simply needed to create a navigationItem property in each of my three view controllers. When the controllers are instantiated in the delegate methods I simply set the navigationItem property equal to that of the detailViewController. That way in my viewDidApper methods I could create the button. Then at viewWillDisappear I set the button to nil. You can also just create the button at viewdidLoad of the DetailViewController and change the text and action in viewDidAppear of the individual viewControllers. Here is a sample.

In the delegate methods

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController

I call a helper method based on the index of the viewController. The helper method instantiates the view controllers when it is called. Once instantiated I set some properties including the navigationItem property.

-(FirstController *)controllerAtIndex:(NSUInteger)index
{

    FirstController *fvc = [self.storyboard instantiateViewControllerWithIdentifier:@"FirstPageController"];
    fvc.imageFile = self.pageImages[index];
    fvc.titleText = self.pageTitles[index];
    fvc.pageIndex = index;
    fvc.navItem = self.navigationItem;
    return fvc;

}

Then in the viewDidAppear of the viewController I just do this

-(void)viewDidAppear:(BOOL)animated
{

    UIBarButtonItem *newButton = [[UIBarButtonItem alloc]
                               initWithTitle:@"Whatever" style:UIBarButtonItemStylePlain target:self action:@selector(doSomething)];
    navItem.rightBarButtonItem = newButton;

}
¿Fue útil?

Solución

If you need the button to change each time you change the page you look at, it must be done in one of the delegate methods that you have tried. I suggest however, that instead of creating a new button and setting it to the navigation item, you simply change the title.

You can create the button in interface builder and link it to a property in your DetailViewController and then call setTitle:forState with UIControlStateNormal on the button every time you go to a new page.

If you need the button to do something different for each page, I would recommend checking the current page in the buttons action method rather than declaring a new one each time.

Otros consejos

You can find the correct navigation item to set buttons/titles on by finding the page controller in one of its paged view controllers, then getting its nav item. e.g.

UIViewController *pageController = [[self.navigationController childViewControllers] lastObject];
pageController.navigationItem.title = @"My page's title";

It's really annoying that self.navigationItem doesn't work!

One of my colleagues experienced the same problem with page view controller.

As far as I understand, you wont' be able to add UIBarButtonItem to navigation bar of member view controllers in UIPageViewController. Reason being 'navigationController' is set to nil for UIPageViewController. To confirm, print value of [UIPageViewController navigationController].

However you can do one thing to overcome this issue. Please download example PhotoScroller.

And do following changes in AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{
// kick things off by making the first page
PhotoViewController *pageZero = [PhotoViewController photoViewControllerForPageIndex:0];

UINavigationController * nav = [[UINavigationController alloc] initWithRootViewController:pageZero];
if (pageZero != nil)
{
    // assign the first page to the pageViewController (our rootViewController)
    UIPageViewController *pageViewController = (UIPageViewController *)self.window.rootViewController;
    pageViewController.dataSource = self;

    [pageViewController setViewControllers:@[nav]
                                  direction:UIPageViewControllerNavigationDirectionForward
                                   animated:NO
                                 completion:NULL];
}
return YES;
}

And following changes in the PhotoViewController.m

- (void)loadView 
{
.....
.....
self.title =@"Frogs";
UIBarButtonItem *newButton = [[UIBarButtonItem alloc] initWithTitle:@"Something" style:UIBarButtonItemStylePlain target:self action:@selector(doSomething)];

[newButton setTintColor:[UIColor redColor]];
self.navigationItem.rightBarButtonItem = newButton;
}

To avoid crash, you have to handle UIPageViewControllerDataSource delegate methods correctly in AppDelegate.m

Though, I wouldn't advice you to do above as it breaks the whole concept of UIPageViewController.

I hope this would be helpful.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top