I can't seem to get a UISearchBar to position itself from the far left to the far right in the navigation bar. In the -(void)viewDidLoad method, I have the following code:
UISearchBar *sb = [[UISearchBar alloc] initWithFrame:self.tableView.tableHeaderView.frame];
sb.delegate = self;
self.navigationItem.titleView = sb;
[sb sizeToFit];
[sb release];
When you build and run, it looks just fine at first glance. However, looking more closely, you can tell there is a margin/space on the left. This wouldn't be a big deal in the grand scheme of things, but when I tap the search bar to start a search, I animate the cancel button into view. Because the search bar is positioned slightly to the right, the animation is jerky and the cancel button falls off the end like so:
link text
It seems as if the UINavigationItem is like a table with three cells, where there is a padding on the first and last which I can't remove - nor does there seem to be a way to 'merge' it all together and then place the search bar there. I know this look is possible, because the AppStore search has a search bar in the navigation bar and it goes all the way to the edges. Anyone know how to get the search bar to go all the way to the edges so my slide-in cancel button animation will work properly?
Actually, there's a really simple solution. All you have to do is create a zero-width view for the back item:
UIView *hackView = [[UIView alloc] initWithFrame:CGRectZero];
UIBarButtonItem *hackItem = [[UIBarButtonItem alloc] initWithCustomView:hackView];
self.navigationItem.backBarButtonItem = hackItem;
[hackView release];
[hackItem release];
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectZero];
[searchBar sizeToFit];
self.navigationItem.titleView = searchBar;
[searchBar release];
Be sure to do this in your loadView method, not init. I'm not sure why that makes a difference, but it does.
Apparently it's about timing. Having it in loadView stopped working for me, but putting it in viewWillAppear works (with a check so that it's only done once, of course). I think the idea is to set the titleView after some initialization has already completed.
The following code hides the navigationBar just for this UIViewController:
- (void)viewWillAppear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:NO animated:animated];
}
So to get the UISearchBar to show in the UINavigationBar's place, on your root view controller just have your search bar where the navigation bar would be normally!
I think I found out the answer - though I haven't tested to verify. In the issue I provided above, I have the following structure:
tab bar controller -> navigation controller -> view controller(s)
The search bar in question was in a view controller, which in turn was in the navigation controller, which navigation controller is in the tab bar.
I was casually watching the Stanford CS 193P (Spring 2009) courses and at the end of Lecture 13, the answer may have been presented. Alan Cannistraro stated that the structure of the Presence app should have this structure:
this structure http://img143.imageshack.us/img143/6/viewcontrollerstructure.jpg
where the bottom view controller (adjacent to the tab bar controller) was the view controller which had the search bar control. He warned if it's not done in this fashion, you'll "run into problems". Possibly the problem I faced? I believe so.
Maybe apple is using an UISearchDisplayController for doing these kinda things.