For the first time I'm subclassing UIToolbar for creating ones with custom UIBarButton.
I'm doing this:
#interface CustomToolbar : UIToolbar
#end
#implementation CustomToolbar
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// add buttons
UIBarButtonItem *myButton = [[UIBarButtonItem alloc] initWithTitle:#"Button" style:UIBarButtonItemStyleBordered target:self action:#selector(pressSignupButton:)];
// add buttons to the array
NSArray *items = [NSArray arrayWithObjects:myButton, nil];
[self setItems:items];
}
return self;
}
#end
Then in my view controller:
CustomToolbar *myToolbar = [[CustomToolbar alloc] init];
[self.navigationController.view addSubview:myToolbar];
The problem is that I can see the toolbar but there aren't buttons. Why?
NB: I prefer to have all programmatically without nib.
Does this work?
CustomToolbar *myToolbar = [[CustomToolbar alloc]
initWithFrame:CGRectMake(0,0,self.navigationController.view.frame.size.width, 44)];
[self.navigationController.view addSubview:myToolbar];
I have subclassed the UIToolbar to make it easier to implement a safari next, previous, done sort of thing.
It all worked fine when i was adding it directly (ie not subclassing) but now that i am, it crashes every time i click one of the buttons with
-[keyboardToolBar hideKeyboard:]: unrecognized selector sent to instance
This is the first time i have attempted to subclass something so im not sure if i have done something the wrong way.
Code for the subclass
#interface keyboardToolBar : UIToolbar {
UIToolbar *keyboard;
UIBarItem *previous;
UIBarItem *next;
UIBarItem *done;
}
#property (nonatomic, retain) UIToolbar *keyboard;
#property (nonatomic, retain) UIBarItem *previous;
#property (nonatomic, retain) UIBarItem *next;
#property (nonatomic, retain) UIBarItem *done;
-(void)previousField;
-(void)nextField;
-(void)hideKeyboard;
#end
#import "keyboardToolBar.h"
#implementation keyboardToolBar
#synthesize keyboard, previous, done, next;
-(UIToolbar*)initWithFrame:(CGRect)frame{
//Create a new toolbar
keyboard = [[UIToolbar alloc]initWithFrame:frame];
//Create all the buttons and point them to methods
UIBarButtonItem *previousButton = [[UIBarButtonItem alloc] initWithTitle:#"Previous"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(previousField:)];
UIBarButtonItem *nextButton = [[UIBarButtonItem alloc] initWithTitle:#"Next"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(nextField:)];
UIBarButtonItem *filler = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
target:nil
action:nil];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle:#"Done"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(hideKeyboard:)];
//Set the width of both of the buttons to make it look pritty
previousButton.width = 70.0f;
nextButton.width = 70.0f;
self.previous = previousButton;
self.next = nextButton;
self.done = doneButton;
//Add the buttons to the toolbar
[keyboard setItems:[[[NSArray alloc] initWithObjects:self.previous, self.next, filler, self.done, nil] autorelease]];
//Release the buttons
[previous release];
[next release];
[filler release];
[done release];
//return the shiny new toolbar
return keyboard;
}
-(void)previousField{
}
-(void)nextField{
}
-(void)hideKeyboard{
NSLog(#"hello");
}
#end
and is called using UIToolbar *keyboard = [[keyboardToolBar alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 50)];
I have tried everything i can think of but still get the same error. Im sure i am just not retaining something somewhere of pointing the buttons to the wrong place but any help would be muchly appreciated
Thanks
Darc
The problem here is that your buttons are calling functions that take an input, but your functions do not take an input:
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle:#"Done"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(hideKeyboard:)];
This means that there must be a method hideKeyboard:(id)sender. But you have
-(void)hideKeyboard{
NSLog(#"hello");
}
Either add the input to the function or remove the : from the selector call.
you effectively wrote it as a class method, here is a little bit better version, because of memory management issues etc.
-(UIToolbar*)initWithFrame:(CGRect)frame{
//Create a new toolbar
if ((self = [super initWithFrame:frame]))
//Create all the buttons and point them to methods
previous = [[UIBarButtonItem alloc] initWithTitle:#"Previous" style:UIBarButtonItemStyleBordered target:self action:#selector(previousField:)];
next = [[UIBarButtonItem alloc] initWithTitle:#"Next" style:UIBarButtonItemStyleBordered target:self action:#selector(nextField:)];
UIBarButtonItem *filler = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
done = [[UIBarButtonItem alloc] initWithTitle:#"Done" style:UIBarButtonItemStyleBordered target:self action:#selector(hideKeyboard:)];
//Set the width of both of the buttons to make it look pritty
previous.width = 70.0f;
next.width = 70.0f;
//Add the buttons to the toolbar
[keyboard setItems:[[[NSArray alloc] initWithObjects:previous, next, filler, done, nil] autorelease]];
//Release the buttons
[previous release];
[next release];
[filler release];
[done release];
//return the shiny new toolbar
return self;
}
also fix your methods to be either
#selector(someAction) to match -(void)someAction;
or #selector(someAction:) to match -(void)someAction:(id)sender;
also no reason to keep a reference to UIToolBar * keyboard, because you want that to be self.
actually probably no reason to keep references to the buttons at all unless you will need to change their titles or action/target pairs later.
You (or something you're doing) is calling hideKeyboard: (note the colon, indicating that the method has one argument.). However, the hideKeyboard method you've implemented, doesn't take any arguments.
Most likely, hideKeyboard should be changed to:
- (void)hideKeyboard:(id)sender {
NSLog(#"hello");
}
As an aside, the usual style for class names is capitalized, so your subclass should be KeyboardToolBar (and I'd also recommend keeping the same camel case as Apple's classes, so KeyboardToolbar would be best).
I've searched around and I can't seem to figure it out. I'm sure many people will have links for me and such, which I've most likely already looked at. But if someone could please just show me code to do the following:
I'd like to have a left arrow in my UINavigationBar as a "Back" UINavigationItem. How can I do this? Here is my current code in my UIViewController:
theBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 48.0f)];
UIBarButtonItem *leftButton = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStyleBordered target:nil action:#selector(backButtonSelected:)];
UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithTitle:#"Options" style:UIBarButtonItemStyleBordered target:nil action:#selector(optionsButtonSelected:)];
UINavigationItem *item = [[UINavigationItem alloc] initWithTitle:#"Title"];
item.leftBarButtonItem = leftButton;
item.hidesBackButton = YES;
item.rightBarButtonItem = rightButton;
[self.view addSubview:theBar];
I think this may be what you're looking for.
// in .h file
#property (nonatomic, retain) UINavigationBar *navBar;
// in .m file just below #implementation
#synthesize navBar;
// within .m method
navBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 48.0f)];
navBar.barStyle = UIBarStyleBlack;
UINavigationItem *title = [[UINavigationItem alloc] initWithTitle:#"Nav Bar Title"];
UIBarButtonItem *leftButton = [[UIBarButtonItem alloc]
initWithTitle:#"Back"
style:UIBarButtonItemStylePlain
target:nil
action:#selector(backButtonSelected:)];
title.leftBarButtonItem = leftButton;
UIBarButtonItem *rightButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAction
target:nil
action:#selector(showActionSheet:)];
title.rightBarButtonItem = rightButton;
[navBar pushNavigationItem:title animated:YES];
[self.view addSubview:navBar];
You should use an UINavigationController in order to pop/push UIViewControllers on your screen. The navigation controller will add an UINavigationBar to your UIViewControllers automatically so you will not need to create them as you did.
Here is a sample. I didn't looked for memory leaks.
In the app delegate you'll find this method:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
MainVC *mainVC = [[MainVC alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:mainVC];
[self.window addSubview:navController.view];
[self.window makeKeyAndVisible];
return YES;
}
MainVC is a UIViewController that represents the level 1 of the hierarchy. in it i have
- (void)loadView
{
self.view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
self.view.backgroundColor = [UIColor redColor];
self.title = #"MainVC";
UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithTitle:#"SecondLevel" style:UIBarButtonItemStyleBordered target:self action:#selector(secondLevelSelected:)];
self.navigationItem.rightBarButtonItem = rightButton;
}
- (void) secondLevelSelected:(id)sender
{
SecondVC *secondVC = [[SecondVC alloc] init];
[self.navigationController pushViewController:secondVC animated:YES];
}
SecondVC is another UIViewController that represents the second level of the hierachy. Here you will find the back button that you want.
- (void)loadView
{
self.view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 240)];
self.view.backgroundColor = [UIColor greenColor];
self.title = #"SecondVC";
self.navigationItem.hidesBackButton = YES;
UIBarButtonItem *leftBtn = [[UIBarButtonItem alloc] initWithTitle:#"FirstLevel" style:UIBarButtonItemStyleBordered target:self action:#selector(leftBtnSelected:)];
self.navigationItem.leftBarButtonItem = leftBtn;
}
- (void) leftBtnSelected:(id)sender
{
[self.navigationController popViewControllerAnimated:YES];
}
I'm trying to disable a button that I add to my navigation controller bar. Here is how I added it:
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithTitle:#"Add" style:UIBarButtonItemStylePlain target:self action:#selector(addNew)];
self.navigationItem.rightBarButtonItem = addButton;
[addButton release];
What is the best way to enable/disable items like these? I've tried this code:
addButton.disabled = YES;
but it doesn't work of course. Any help would be appreciated. Thanks.
Edit: Should be addButton.enabled = YES;
Oops
If you define addButton in your header, and #synthesize it, then you will be able to use addButton.enabled = NO;, there is no "disabled" setter.
.h
#interface MyViewController {
UIBarButtonItem *addButton;
}
#property(nonatomic,retain) UIBarButtonItem *addButton;
#end
.m
#implementation MyViewController
#synthesize addButton;
-(void)viewDidLoad{
addButton = [[UIBarButtonItem alloc] initWithTitle:#"Add" style:UIBarButtonItemStylePlain target:self action:#selector(addNew)];
self.navigationItem.rightBarButtonItem = addButton;
[addButton release];
}
-(void)DoSomething{
addButton.enabled = NO;
}
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;
}
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.
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.
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.
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.
It should look like this:
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.
That will give you the default Refresh icon.
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.
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 {
}
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
-(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];
}
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
You can try
self.navigationBar.topItem.rightBarButtonItem = anotherButton;
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
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];
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 !?")
}
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];
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;
UIBarButtonItem *rightBarButtonItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(add:)];
self.navigationItem.rightBarButtonItem = rightBarButtonItem;
- (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");
}
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];
}
You should add your barButtonItem in - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated method.
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
}
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.
Go to the main.storyboard.
Select that new view Controller.
Go to the document outline.
Check view Controller contents.
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.
save and clean the project.
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];
}
#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];