adding UIButton to UIView or UINavigationBar doesn't work - iphone

I am trying to add a UIButton to a UINavigationBar with the following:
UIButton * addSource = [UIButton buttonWithType:UIButtonTypeCustom];
[addSource setBackgroundImage:[UIImage imageNamed:#"addsource.png"] forState:UIControlStateNormal];
[addSource addTarget: self action:#selector(addSourceButton:) forControlEvents:UIControlEventTouchUpInside];
[addSource setFrame: CGRectMake(115, 5, 32, 32)];
[navBar addSubview:addSource];
[addSource release];
However this doesn't work, any idea? When I comment out the setBackgroundImage and change it to setBackgroundColor I can see it, but I can't seem to click on it (i.e: the action in which it's set to is not triggered). Any idea? Changing it to a UIImageView instead of a UIButton also works, I can see the image just fine, so this clarifies that the image is there.

You can not add a UIButton to a UINavigationBar. Use a UIBarButtonItem.
From Apple docs:
Unlike other types of views,
you do not add subviews to a navigation bar directly. Instead, you use
a navigation item (an instance of the UINavigationItem class) to
specify what buttons or custom views you want displayed.
and:
A bar button item is a button specialized for placement on a UIToolbar
or UINavigationBar object. It inherits basic button behavior from its
abstract superclass, UIBarItem. The UIBarButtonItem defines additional
initialization methods and properties for use on toolbars and
navigation bars.

”
Adding Content to a Navigation Bar
When you use a navigation bar as a standalone object, you are responsible for providing its contents. Unlike other types of views, you do not add subviews to a navigation bar directly. Instead, you use a navigation item (an instance of the UINavigationItem class) to specify what buttons or custom views you want displayed. A navigation item has properties for specifying views on the left, right, and center of the navigation bar and for specifying a custom prompt string.
A navigation bar manages a stack of UINavigationItem objects. Although the stack is there mostly to support navigation controllers, you can use it as well to implement your own custom navigation interface. The topmost item in the stack represents the navigation item whose contents are currently displayed by the navigation bar. You push new navigation items onto the stack using the pushNavigationItem:animated: method and pop items off the stack using the popNavigationItemAnimated: method. Both of these changes can be animated for the benefit of the user.
In addition to pushing and popping items, you can also set the contents you could also use of the stack directly using either the items property or the setItems:animated: method. You might use these methods at launch time to restore your interface to its previous state or to push or pop more than one navigation item at a time.
If you are using a navigation bar as a standalone object, you should assign a custom delegate object to the delegate property and use that object to intercept messages coming from the navigation bar. Delegate objects must conform to the UINavigationBarDelegate protocol. The delegate notifications let you track when navigation items are pushed or popped from the stack. You would use these notifications to update the rest of your application’s user interface.
For more information about creating navigation items, see UINavigationItem Class Reference. For more information about implementing a delegate object, see UINavigationBarDelegate Protocol Reference."
from UiNavigationBar class reference.
please also refer UIBarButoonItem -(id)initWithCustomView:(UIView*)view. pleae note UIbutton is subclass of uiview
also refer uinavbaritem's
rightBarButtonItem property
– setLeftBarButtonItems:animated:
– setLeftBarButtonItem:animated:
– setRightBarButtonItems:animated:
– setRightBarButtonItem:animated:
and titleview.

you have to use a UIBarButton item, heres the code:
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:#selector(dismissView)];
self.navigationItem.leftBarButtonItem = cancelButton;
[cancelButton release];

If you want to add something in the centre in your navigation bar, why don't you just do
navbar.titleView = addSource

Related

How to modify a UIBarButtonItem view programmatically after it's been setup in Interface Builder?

I have created a UIBarButton item in Interface Builder and linked it to a UIBarButton item property in the class. In Interface Builder it's Style = Plain and Identifier = Custom and it's Title is blank.
Inside the class file on the viewDidLoad method I am trying to add a custom view to this UIBarButtonItem property.
E.g
UISegmentedControl *newButton = [[UISegmentedControl alloc] initWithItems:....];
newButton.momentary = YES;
newButton.segmentedControlStyle = UISegmentedControlStyleBar;
newButton.tintColor = [UIColor .....];
[self.myBarButtonItem setCustomView:newButton];
and this results in NOTHING showing up at all. Why is that?
I've read that if I create the UIBarButtonItem programmatically:
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:newButton];
and then add this BarButtonItem to the toolbar - it would work. My issue is I have lots of stuff going on my toolbar and this UIBarButton item needs to be on the FAR right of the toolbar and if I can't link to it directly in interface builder, then I'd have to build out ALL my toolbar items programmatically to get the layout I need going.
So is there a way to do this with a customView when linking to a UIBarButtonItem created in IB?
Thanks!
To change stuff that's on a UIToolBar you use it's items property. That should answer your question : How to programmatically replace UIToolBar items built in IB
Edit:
The way i like to work with those, is make a bunch of IBOutlets in the view controller class for each uibarbuttonitem. In Interface Builder, i put the first (default) items to be on the toolbar normally as a toolbar subview and all that, and the rest of them i put as top level items in the xib (same level as the view that is connected to the view controller's .view property outlet). That way i don't have to programatically create them. And still have them hidden to later attach them to the uitolbar.
If you use this approach than don't forget to call release on the top level IBOutlets if you use ivar IBOutlets (as opposed to #property IBOutlets) as all top level objects in a xib that aren't connected to a KVC compilant reference.

How to reliably place built-in UINavigationController UIToolbar on top of iPad view

I am trying to use the UINavigationController object's built-in UIToolbar object in my iPad application, but I want it to be displayed on top of the view instead of the bottom, which is where it defaults.
I am also hiding the UINavigationController object's Navigation Bar.
In order to make this work, I had to write the following code:
navigationController.navigationBarHidden = YES;
navigationController.toolbarHidden = NO;
navigationController.toolbar.frame = CGRectMake(0, 0, 768, 44);
This solution works with one exception: when the application Enters Background and Becomes Active again, the Toolbar is always repositioned on the bottom of the view.
I've tried moving the code from viewDidLoad to viewDidAppear:animated, and it still behaves this way.
First, is there any better way to approach this, and if not, how can I stop the Toolbar from being repositioned?
I've also instead decided to use my own UIToolbar object and add it to each view via a custom Base UIViewController class' viewDidLoad. However, this causes the Toolbar to animate when each view is pushed or popped because it is actually part of the view, which just seems "hokey".
Any ideas on possible solutions?
Thanks everyone!
It says in the documentation under UINavigationController's toolbar property that:
Access to this toolbar is provided solely for clients that want to present an action sheet from the toolbar. You should not modify the UIToolbar object directly.
This is sort of hackish, but you could make a UIToolbar yourself and add it directly to the window (i.e. over the navigation controller.)
You can use the category below to modify the UIToolbar class to achieve what you're after.
#implementation UIToolbar (setCenter)
-(void)setCenter:(CGPoint)center
[super setCenter:CGPointMake(384, 22)];
}
#end
The toolbar has limited functionality when used with a UINavigationController. It only provides a convenient way to manage the actionsheet in the toolbar.
From the docs: "Access to this toolbar is provided solely for clients that want to present an action sheet from the toolbar. You should not modify the UIToolbar object directly."
The solution I would use is to create a subclass of UIView with convenience methods to manage your actionsheet and any other custom functionality you need. This custom view can be shared across all views in the UINavigationController and placed where ever you like in the parent view. This will give you ultimate control of your custom top placed toolbar.

iPhone: Is it possible to have an 'info'-button in all views in my app?

As mentioned in the title, how do I implement such a functionality?
I am using the code below, (in my viewDidLoad), to get the button on my Navigation Controller of my main view.
UIButton* infoButton = [UIButton buttonWithType:UIButtonTypeInfoLight];
[infoButton addTarget:self action:#selector(viewWillAppear:) forControlEvents:UIControlEventTouchUpInside];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:infoButton];
Not sure how I can get it displayed in all my views.
Each view pushed to the navigation stack has an own navigation bar. So I afraid you have to add this button to each navigation bar, when you create a view and before you push this view to the navigation stack.
You could simply add an info button to the window, instead of creating a new button for each view controller. Since the window never changes, the button will always be on screen. You only have to take care that no other views are on top of the button.
I would suggest you create an base view controller, and add the bar button to your navigationItem in viewDidLoad. Then all your view controllers subclass from the base controller, rather than the default UIViewController. This should solve your problem.

Using IB to add a UISegmentedControl to a NavigationBar

I'm current creating a UISegmentedControl programmatically in a view controller's viewDidLoad method and adding it to the view controller's navigation bar by assigning it to self.navigationItem.titleView.
That's easy enough, but I'd like to be able to do this in Interface Builder as well and so far haven't been able to figure out how. Google hasn't been much help either. Can someone describe how to do this in IB or point to an online example? I'd be much appreciative.
Thanks,
Howard
If you've got whole nav stack in the nib, it's actually pretty easy; you can just drag it into the title area and IB does the right thing automatically.
Otherwise, you can just add the segmented control to the nib (not necessarily a subview) and then add an #property IBOutlet to it from your view controller. Then in viewDidLoad, assign it to the titleView as normal. Remember to release in dealloc, and you're golden.
In IB you certainly can just drag a view into the middle of the navigation controller and it will work fine if its just inside one navigation item.
However, if the same view object reference is dragged into the title view area of different navigation items that will at some point be pushed onto the navigation controllers stack, you will run into problems with the title view disappearing when you travel back through the stack. The navigation controller isn't too happy with references to the same object popping up on multiple navigation items for some reason and it only throws a fit when you pop back to the view with the troublesome navigation item.
To get around this you MUST explicitly set and unset the titleView object when the you navigate to the views using the shared title view object reference. For instance, if you had custom logic behind a subclassed view set as the titleView that you only wanted to instantiate once.
Alternatively, you could store the UISegmentedControl designed in IB in it's own NIB. Then set the FileOwner to the viewcontroller class that will be using the segmentedControl instance. In the viewcontroller class, declare the segmentedcontrol as an IBOutlet Property and link it to the instance in the nib.
All left to using the designed instance is then to call:
[[NSBundle mainBundle] loadNibNamed:#"TTCustomSegmentedControl"
owner:self
options:nil];
self.navigationItem.titleView = sortSegmentControl;
Just try this (works for me):
UISegmentedControl *mSegmentedControl = [[UISegmentedControl alloc] initWithItems:
[NSArray arrayWithObjects:
#"Segment 1",
#"Segment 2",
nil]];
mSegmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
mSegmentedControl.tintColor = [UIColor redColor];
[mSegmentedControl setSelectedSegmentIndex:0];
[mSegmentedControl addTarget:self action:#selector(sectionPress:)
forControlEvents:UIControlEventValueChanged];
self.navigationItem.titleView = mSegmentedControl;
You can't set the titleView property in IB, but you may be able to create / set up the control as a child of your controller's view via Interface Builder, and then in your viewDidLoad method, remove it from your view and set it as the titleView:
[segControl removeFromSuperview];
self.navigationItem.titleView = segControl;

iphone custom navigationBar singleton or not?

I am using my own custom navigationBar, but i need to access it in a number of different views because i need to add buttons, change title and so forth.
Should i pass a reference to my navigationBar each time i show a new view, or just make it a singleton so i can access it from any view?
Neither.
You've listed adding buttons and changing titles as the reasons you need a custom toolbar, but both of those things can be done through the navigation controller with no need to create your own and therefore no need to create a singleton or a global variable.
When you push a new view controller, you can set the title for the navigation bar simply by calling [self setTitle:#"Nav Title"]; in the -viewDidLoad of that view controller. If you need to add a button, use code like the following (also in -viewDidLoad):
[[self navigationItem] setRightBarButtonItem:[[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemEdit
target:self
action:#selector(setEditing)] autorelease]];
In other words, your design is flawed if you are creating a custom navigation bar only for the reasons you've listed. I suppose there are some good reasons to create a custom navigation bar, but these are not among them.
Consider reviewing the Configuring the Navigation Item Object section of the View Controller Programming Guide for iPhone OS.
Best regards,
Are you using a UINavigationController? If so, you can access the navigation bar from any sub-controller like this:
UINavigationBar *bar = self.navigationController.navigationBar;
Make it a global variable.