Iphone – UISearchBar and UINavigationItem

iphoneuinavigationitemuisearchbar

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?

Best Answer

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.

Related Topic