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;
Related
I'm programmatically creating a UITableViewController class that shows a table view with a simple navigation bar (though without a UINavigationController, as there are no further levels to the table view hierarchy).
Here is the relevant code:
- (void)viewWillAppear:(BOOL)animated {
UINavigationBar *navBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 44.0f)];
[self.tableView addSubview:navBar];
}
However, the navigation bar covers most of the first table view cell, and scrolls with the whole view.
How can I fixate the navigation bar above the table view, and keep it from scrolling through code?
The problem is that you are using UITableViewController. Switch to a standard UIViewController, add the tableview delegate and datasource methods, point the tableview to those methods, and then you do what you want to do. You could also add a UIToolbar in the XIB and create it that way if you wish.
If you really want a navigation bar, then use an NSNavigationView controller.
When you use a navigation controller, it takes care of this for you, but the navigation bar is just another subview. The remedy is to frame your table view relative to the navigation bar.
self.tableView.frame = CGRectMake(0,myNavBar.frame.size.height, 320, self.view.frame.size.height-myNavBar.frame.size.height);
Set the navigation bar's translucent property to NO:
self.navigationController.navigationBar.translucent = NO;
Having a hierarchy of data doesn't really drive whether or not you need to use a UINavigationController. There are three good reasons to go ahead and just use the UINavigationController.
You get the Navigation Bar for free, and the Nav Controller handles setting the proper frame of your root view controller when you set the nav controller's root view controller property to your view controller
If you one day wake up and say, "Hey! I want to add another layer of information to my awesome app!", you don't need to make any changes to the overall design (or, at most, minimal ones).
As my comment to #danh's suggestion implies, you're immune to whatever whacky changes Apple may decide to do with regards to nav bar height.
The solution to this behavior would be to add the UINavigationBar to the Parent View Controller's view:
[self.parentViewController.view addSubview:myNavBar];
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
I have a Custom TabViewController that adds subviews to the current view depending on what UITabBarItem is selected. For the different subviews I have simulated a Navigation Bar and a Tab Bar so that the sub views match the format when they are displayed. The one sub view, which contains a UILabel, displays fine however the sub view with the UITableView overlaps the UITabBar. However in the Interface Builder I have sized the UITableView to not cut off the UITabBar.
Adding the subview in the TabViewController
[self.view addSubview:subViewController.view];
You haven't provided enough information to be sure, but I think you are adding the table view to the wrong view. Assuming that self is your UITabBarController subclass, you are adding the custom view in the view that covers the entire screen, including the tab bar.
Instead, you should be adding the custom views to the selected view controller's view:
[self.selectedViewController.view addSubview:subViewController.view];
This will limit the stuff you are adding to the tab bar controller's content area, and won't overlap the tab bar.
I'm not sure what you are trying to accomplish with this approach, though: it seems like it would make more sense to add subViewController to the set of view controllers that the UITabBarController manages, rather than messing around with the view hierarchy.
Also, there is nothing inherently wrong with loading views from a nib and then manipulating them in code. "Mixing styles" is not a problem.
As Legolas stated, it seems like you are mixing styles here. Given that it sounds like you need to push it from the code, you could try full instantiation of the object from the code, for example:
UITableView *table = [[UITableView alloc] initWithFrame:CGRectMake(x, y, width, height)];
table.delegate = self; //or whatever the delegate is
table.dataSource = self; //or wherever the datasource is
...then add it to whatever view you need to.
If that all fails, double check your nib and make sure you have the proper options set for whether a tab bar is being shown, nav bar, etc, as that will effect the size.
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.
I wanted to add a view to the bottom of my screen. The controller is a UITableViewController, how do I shrink the tableView and add a extra view at the bottom of the tableview?
I've tried setting the frame of self.tableView in different places (viewDidLoad, viewWillAppear etc) but nothing happens. The tableView is created by IB and not programtically.
I've tried added a footer to my table view but that's not what I want, because the footer actually scrolls up, I want a static non moving View at the bottom of the screen.
I'm not saying you can't do it otherwise, but you may not want a UITableViewController for this situation. You can still have your view controller implement UITableViewDelegate and UITableViewDataSource, but place a vanilla UIView in your nib, into which you place a UITableView. Then just make sure to set the view outlet to the UIView containing your table. This has the effect of allowing you to create your additional view within IB. I just tried this and it appeared to work.
I'm guessing you're using a UINavigationController. When you push a controller onto your navigation stack, UINavigationController resizes its view to full screen, ignoring the geometry and autoresizing behavior you've defined in IB.
This resizing seems to happen after viewWillAppear:. In the past I've had some success resizing a table view and adding a sibling view in viewDidAppear:, after calling [super viewDidAppear:]. This is a bit risky though, since Apple could break it by changing how UINavigationController works behind the scenes.
A safer option is to push a view controller onto your navigation stack that controls a wrapper view. Then add your UITableView and its sibling as subviews of that wrapper view. The annoying thing about this option is that you'll probably want to use a nested UITableViewController to manage your non-full screen table view, but the documentation for UIViewController says it's designed to manage full screen views only. If you decide to ignore this admonition and nest your view controllers anyway, you'll find that viewWill/DidAppear/Disappear don't get called on the nested controller, so you'll have to manually delegate those methods from your wrapper view controller. This lack of support for nested controllers is one of my biggest pet peeves about UIKit, and I've gone to great lengths to engineer around it.
If you want to toe the line and use view controllers only for full screen views, you can push a normal view controller that controls your full screen wrapper view, manually implement all the UITableViewDataSource and UITableViewDelegate methods in your view controller, and set it as the delegate for your table view.
you want to change the -loadView method. Not viewDidLoad or viewWillAppear. This will allow you to make additional configurations with your tableview even if it is created in IB.
- (void)loadView {
[super loadView];
CGRect titleRect = CGRectMake(0, 0, 300, 40);
UILabel *tableTitle = [[UILabel alloc] initWithFrame:titleRect];
tableTitle.textColor = [UIColor blueColor];
tableTitle.backgroundColor = [self.tableView backgroundColor];
tableTitle.opaque = YES;
tableTitle.font = [UIFont boldSystemFontOfSize:18];
tableTitle.text = [curTrail objectForKey:#"Name"];
self.tableView.tableHeaderView = tableTitle;
[self.tableView reloadData];
[tableTitle release];
}
I don't know how to do it in IB but the way to do it in code is with this:
- (void) loadView
{
UITableView *tv = [[UITableView alloc] initWithFrame: rect
style: UITableViewStyleGrouped];
// finishg configuring table view
self.view = tv;
[tv release];
}
Trying to do it in two stages -- style first and then frame or frame first and then style -- neither of them works.