192

I am trying to add a refresh button to the top bar of a navigation controller with no success.

Here is the header:

@interface PropertyViewController : UINavigationController {

}

Here is how I am trying to add it:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        UIBarButtonItem *anotherButton = [[UIBarButtonItem alloc] initWithTitle:@"Show" style:UIBarButtonItemStylePlain
                                          target:self action:@selector(refreshPropertyList:)];      
        self.navigationItem.rightBarButtonItem = anotherButton;
    }
    return self;
}
lambmj
  • 1,843
  • 2
  • 21
  • 27
Artilheiro
  • 4,005
  • 10
  • 36
  • 34

21 Answers21

362

Try doing it in viewDidLoad. Generally you should defer anything you can until that point anyway, when a UIViewController is inited it still might be quite a while before it displays, no point in doing work early and tying up memory.

- (void)viewDidLoad {
  [super viewDidLoad];

  UIBarButtonItem *anotherButton = [[UIBarButtonItem alloc] initWithTitle:@"Show" style:UIBarButtonItemStylePlain target:self action:@selector(refreshPropertyList:)];          
  self.navigationItem.rightBarButtonItem = anotherButton;
  // exclude the following in ARC projects...
  [anotherButton release];
}

As to why it isn't working currently, I can't say with 100% certainty without seeing more code, but a lot of stuff happens between init and the view loading, and you may be doing something that causes the navigationItem to reset in between.

danh
  • 62,181
  • 10
  • 95
  • 136
Louis Gerbarg
  • 43,356
  • 8
  • 80
  • 90
  • 46
    I you are doing this outside of the UINavigationController subclass, you would refer to it like this: someNavController.topLevelController.navigationItem.rightBarButtonItem = anotherButton – ransomweaver Oct 01 '10 at 16:58
  • 2
    I was implementing the suggested solution and my app kept getting crashed until I realized that the @selector method name has to end in colon (:). – Stealth Mar 10 '12 at 15:38
  • 10
    Even inside of a UINavigationContoller's viewDidLoad method, I had to call it like `self.topViewController.navigationItem.leftBarButtonItem = nextButton;` – Joseph Sep 02 '12 at 19:10
38

Try adding the button to the navigationItem of the view controller that is going to be pushed onto this PropertyViewController class you have created.

That is:

MainViewController *vc = [[MainViewController alloc] initWithNibName:@"MainViewController" bundle:nil];
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeInfoLight];
[infoButton addTarget:self action:@selector(showInfo) forControlEvents:UIControlEventTouchUpInside];
vc.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:infoButton] autorelease];

PropertyViewController *navController = [[PropertyViewController alloc] initWithRootViewController:vc];

Now, this infoButton that has been created programatically will show up in the navigation bar. The idea is that the navigation controller picks up its display information (title, buttons, etc) from the UIViewController that it is about to display. You don't actually add buttons and such directly to the UINavigationController.

pablasso
  • 2,479
  • 2
  • 26
  • 32
Adam
  • 433
  • 5
  • 11
  • 2
    Setting the rightBarButtonItem directly on the UINavigationController did not work for me (as proposed by Louis Gerbarg above). Instead setting the item directly on the UIViewController at hand like Adem suggests worked! – leviathan Jun 04 '10 at 08:25
  • 4
    +1 for __"Try adding the button to the navigationItem of the view controller that is going to be pushed"__! – Kjuly Jan 07 '13 at 06:38
25

It seems that some people (like me) may come here looking for how to add a navigation bar button in the Interface Builder. The answer below shows how to do it.

Add a Navigation Controller to your Storyboard

Select your View Controller and then in the Xcode menu choose Editor > Embed In > Navigation Controller.

enter image description here

Alternatively, you could add a UINavigationBar from the Object Library.

Add a Bar Button Item

Drag a UIBarButtonItem from the Object Library to the top navigation bar.

enter image description here

It should look like this:

enter image description here

Set the Attributes

You could double-click "Item" to change the text to something like "Refresh", but there is an actual icon for Refresh that you can use. Just select the Attributes Inspector for the UIBarButtonItem and for System Item choose Refresh.

enter image description here

That will give you the default Refresh icon.

enter image description here

Add an IB Action

Control drag from the UIBarButtonItem to the View Controller to add an @IBAction.

class ViewController: UIViewController {

    @IBAction func refreshBarButtonItemTap(sender: UIBarButtonItem) {
        
        print("How refreshing!")
    }
    
}

That's it.

Community
  • 1
  • 1
Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
  • Sorry, I can't quite follow what you talking about. Try making a new question with an image illustrating what you are talking about. Then add a link to it here. – Suragch Mar 02 '16 at 15:47
  • @Suragch, how can I do the same things with xib files instead of storyboards? , thanks – Cristian Mar 28 '16 at 03:24
  • @CristianChaparroA. Usually xib files are for single views and the navigation bar (that hosts the bar button items) is for multiple views. I've never used an xib with bar button items. You could try asking a new question and then link to it here. – Suragch Mar 28 '16 at 04:30
14

There is a default system button for "Refresh":

- (void)viewDidLoad {
    [super viewDidLoad];

    UIBarButtonItem *refreshButton = [[[UIBarButtonItem alloc] 
                            initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
                            target:self action:@selector(refreshClicked:)] autorelease];
    self.navigationItem.rightBarButtonItem = refreshButton;

}

- (IBAction)refreshClicked:(id)sender {

}
Manni
  • 11,108
  • 15
  • 49
  • 67
11

You can use this:

Objective-C

UIBarButtonItem *rightSideOptionButton = [[UIBarButtonItem alloc] initWithTitle:@"Right" style:UIBarButtonItemStylePlain target:self action:@selector(rightSideOptionButtonClicked:)];          
self.navigationItem.rightBarButtonItem = rightSideOptionButton;

Swift

let rightSideOptionButton = UIBarButtonItem()
rightSideOptionButton.title = "Right"
self.navigationItem.rightBarButtonItem = rightSideOptionButton
Vandit Mehta
  • 2,572
  • 26
  • 41
6
-(void) viewWillAppear:(BOOL)animated
{

    UIButton *btnRight = [UIButton buttonWithType:UIButtonTypeCustom];
    [btnRight setFrame:CGRectMake(0, 0, 30, 44)];
    [btnRight setImage:[UIImage imageNamed:@"image.png"] forState:UIControlStateNormal];
    [btnRight addTarget:self action:@selector(saveData) forControlEvents:UIControlEventTouchUpInside];
    UIBarButtonItem *barBtnRight = [[UIBarButtonItem alloc] initWithCustomView:btnRight];
    [barBtnRight setTintColor:[UIColor whiteColor]];
    [[[self tabBarController] navigationItem] setRightBarButtonItem:barBtnRight];

}
Gaurav Gilani
  • 1,584
  • 14
  • 18
6

For swift 2 :

self.title = "Your Title"

var homeButton : UIBarButtonItem = UIBarButtonItem(title: "LeftButtonTitle", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("yourMethod"))

var logButton : UIBarButtonItem = UIBarButtonItem(title: "RigthButtonTitle", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("yourMethod"))

self.navigationItem.leftBarButtonItem = homeButton
self.navigationItem.rightBarButtonItem = logButton
fandro
  • 4,833
  • 7
  • 41
  • 62
6

You can try

self.navigationBar.topItem.rightBarButtonItem = anotherButton;
MinnuKaAnae
  • 1,646
  • 3
  • 23
  • 35
user2999133
  • 96
  • 1
  • 3
5

Here is the solution in Swift (set options as needed):

var optionButton = UIBarButtonItem()
optionButton.title = "Settings"
//optionButton.action = something (put your action here)
self.navigationItem.rightBarButtonItem = optionButton
vontell
  • 342
  • 3
  • 17
4

Why are you subclasses UINavigationController? There is no need to subclass it if all you need to do is add a button to it.

Set up a hierarchy with a UINavigationController at the top, and then in your root view controller's viewDidLoad: method: set up the button and attach it to the navigation item by calling

[[self navigationItem] setRightBarButtonItem:myBarButtonItem];
pablasso
  • 2,479
  • 2
  • 26
  • 32
Jasarien
  • 58,279
  • 31
  • 157
  • 188
  • 1
    That is a good question. What I am trying to do is actually a very common design pattern, which is a basic tab controller with a navigation controller for each tab. If there is a better way I am open for suggestions. Maybe I should ask that question too. – Artilheiro Aug 03 '09 at 16:42
3

Swift 4 :

override func viewDidLoad() {
    super.viewDidLoad()

    navigationItem.leftBarButtonItem = UIBarButtonItem(title: "tap me", style: .plain, target: self, action: #selector(onButtonTap))
}

@objc func onButtonTap() {
    print("you tapped me !?")
}
ergunkocak
  • 3,334
  • 1
  • 32
  • 31
2
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 110, 50)];
view.backgroundColor = [UIColor clearColor];

UIButton *settingsButton =  [UIButton buttonWithType:UIButtonTypeCustom];
[settingsButton setImage:[UIImage imageNamed:@"settings_icon_png.png"] forState:UIControlStateNormal];
[settingsButton addTarget:self action:@selector(logOutClicked) forControlEvents:UIControlEventTouchUpInside];
[settingsButton setFrame:CGRectMake(40,5,32,32)];
[view addSubview:settingsButton];

UIButton *filterButton =  [UIButton buttonWithType:UIButtonTypeCustom];
[filterButton setImage:[UIImage imageNamed:@"filter.png"] forState:UIControlStateNormal];
[filterButton addTarget:self action:@selector(openActionSheet) forControlEvents:UIControlEventTouchUpInside];
[filterButton setFrame:CGRectMake(80,5,32,32)];
[view addSubview:filterButton];



self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:view];
Sandeep
  • 1,094
  • 9
  • 6
2

Try this.It work for me.

Navigation bar and also added background image to right button.

 UIBarButtonItem *Savebtn=[[UIBarButtonItem alloc]initWithImage:[[UIImage    
 imageNamed:@"bt_save.png"]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] 
 style:UIBarButtonItemStylePlain target:self action:@selector(SaveButtonClicked)];
 self.navigationItem.rightBarButtonItem=Savebtn;
Jaywant Khedkar
  • 5,941
  • 2
  • 44
  • 55
0
    UIBarButtonItem *rightBarButtonItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(add:)];
self.navigationItem.rightBarButtonItem = rightBarButtonItem;
0
- (void)viewWillAppear:(BOOL)animated
{    
    [self setDetailViewNavigationBar];    
}
-(void)setDetailViewNavigationBar
{
    self.navigationController.navigationBar.tintColor = [UIColor purpleColor];
    [self setNavigationBarRightButton];
    [self setNavigationBarBackButton];    
}
-(void)setNavigationBarBackButton// using custom button 
{
   UIBarButtonItem *leftButton = [[UIBarButtonItem alloc] initWithTitle:@"  Back " style:UIBarButtonItemStylePlain target:self action:@selector(onClickLeftButton:)];          
   self.navigationItem.leftBarButtonItem = leftButton;    
}
- (void)onClickLeftButton:(id)sender 
{
   NSLog(@"onClickLeftButton");        
}
-(void)setNavigationBarRightButton
{

  UIBarButtonItem *anotherButton = [[UIBarButtonItem alloc] initWithTitle:@"Show" style:UIBarButtonItemStylePlain target:self action:@selector(onClickrighttButton:)];          
self.navigationItem.rightBarButtonItem = anotherButton;   

}
- (void)onClickrighttButton:(id)sender 
{
   NSLog(@"onClickrighttButton");  
}
tv.ashvin
  • 705
  • 2
  • 7
  • 13
0
    self.navigationItem.rightBarButtonItem =[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(refreshData)];



}

-(void)refreshData{
    progressHud= [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
    [progressHud setLabelText:@"拼命加载中..."];
    [self loadNetwork];
}
Gank
  • 4,507
  • 4
  • 49
  • 45
0

You should add your barButtonItem in - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated method.

Nazik
  • 8,696
  • 27
  • 77
  • 123
Retik
  • 1
0

Just copy and paste this Objective-C code.

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self addRightBarButtonItem];
}
- (void) addRightBarButtonItem {
    UIButton *btnAddContact = [UIButton buttonWithType:UIButtonTypeContactAdd];
    [btnAddContact addTarget:self action:@selector(addCustomerPressed:) forControlEvents:UIControlEventTouchUpInside];
    UIBarButtonItem *barButton = [[UIBarButtonItem alloc] initWithCustomView:btnAddContact];
    self.navigationItem.rightBarButtonItem = barButton;
}

#pragma mark - UIButton
- (IBAction)addCustomerPressed:(id)sender {
// Your right button pressed event
}
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Vivek
  • 4,916
  • 35
  • 40
0

This issue can occur if we delete the view controller or try to add new view controller inside the interface builder(main.storyboard). To fix this issue, it requires to add "Navigation Item" inside new view controller. Sometimes it happens that we create new view controller screen and it does not connect to "Navigation Item" automatically.

  1. Go to the main.storyboard.
  2. Select that new view Controller.
  3. Go to the document outline.
  4. Check view Controller contents.
  5. If new view controller does not have a Navigation item then, copy Navigation item from previous View Controller and paste it into the new view controller.
  6. save and clean the project.
NilamK
  • 1
  • 2
0

Also you are able to add multiple buttons using rightBarButtonItems

-(void)viewDidLoad{

    UIBarButtonItem *button1 = [[UIBarButtonItem alloc] initWithTitle:@"button 1" style:UIBarButtonItemStylePlain target:self action:@selector(YOUR_METHOD1:)];
    UIBarButtonItem *button2 = [[UIBarButtonItem alloc] initWithTitle:@"button 2" style:UIBarButtonItemStylePlain target:self action:@selector(YOUR_METHOD2:)];

    self.navigationItem.rightBarButtonItems = @[button1, button2];
}
yoAlex5
  • 29,217
  • 8
  • 193
  • 205
-1

@Artilheiro : If its a navigationbased project, u can create BaseViewController. All other view will inherit this BaseView. In BaseView u can define generic methods to add right button or to change left button text.

ex:

@interface BaseController : UIViewController {

} - (void) setBackButtonCaption:(NSString *)caption;

(void) setRightButtonCaption:(NSString *)caption selectot:(SEL )selector;

@end // In BaseView.M

(void) setBackButtonCaption:(NSString *)caption {

UIBarButtonItem *backButton =[[UIBarButtonItem alloc] init];

backButton.title= caption;
self.navigationItem.backBarButtonItem = backButton;
[backButton release];

} - (void) setRightButtonCaption:(NSString *)caption selectot:(SEL )selector {

  UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] init];
rightButton.title = caption;

rightButton.target= self;

[rightButton setAction:selector];

self.navigationItem.rightBarButtonItem= rightButton;

[rightButton release];

}

And now in any custom view, implement this base view call the methods:

@interface LoginView : BaseController {

In some method call base method as:

SEL sel= @selector(switchToForgotPIN);

[super setRightButtonCaption:@"Forgot PIN" selectot:sel];

iPhoneDev
  • 2,995
  • 4
  • 33
  • 44