I am attempting to add a UISearchBar
(with its corresponding search logic) but there is a problem: I am using the UITableViewController
subclass's automatically generated UITableView
instead of a separate nib
file, and manipulating everything programmatically in terms of the table view.
In Interface Builder, there is an option to add a Search Bar and Search Display Controller to a nib
. Is there a way to accomplish this same task programmatically or is it in my favor to abandon the default UITableView
and transfer to a custom UITableView
nib file so that I can easily add the UISearchbar
?
Also, I have tried testing out just adding a Search Bar to my UITableView
header (which is where I want it to go) via the following code in my viewDidLoad
implementation, but it shows up behind table section header and hence is invisible unless the table is scrolled down to show what would otherwise be white space. What's up with this?
UISearchBar *testbar = [[UISearchBar alloc] init];
[[self tableView] setTableHeaderView:testbar];
To add a UISearchBar to a UITableView there are these things to do:
ViewController.h:
#import
@interface ViewController : UITableViewController
{
NSArray *originalData;
NSMutableArray *searchData;
UISearchBar *searchBar;
UISearchDisplayController *searchDisplayController;
}
@end
I also added 2 delegates to the class: UISearchBarDelegate and UISearchDisplayDelegate, without, the searchBar simply doesn’t work!
Initialize data:
//ViewController.m
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
NSArray *group1 = [[NSArray alloc] initWithObjects:@"Napoli", @"Juventus", @"Inter", @"Milan", @"Lazio", nil];
NSArray *group2 = [[NSArray alloc] initWithObjects:@"Real Madrid", @"Barcelona", @"Villareal", @"Valencia", @"Deportivo", nil];
NSArray *group3 = [[NSArray alloc] initWithObjects:@"Manchester City", @"Manchester United", @"Chelsea", @"Arsenal", @"Liverpool", nil];
originalData = [[NSArray alloc] initWithObjects:group1, group2, group3, nil];
searchData = [[NSMutableArray alloc] init];
}
return self;
}
Now we need to initialize our two object, I commented the code to explain what I do:
//ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
/*the search bar widht must be > 1, the height must be at least 44
(the real size of the search bar)*/
searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
/*contents controller is the UITableViewController, this let you to reuse
the same TableViewController Delegate method used for the main table.*/
searchDisplayController.delegate = self;
searchDisplayController.searchResultsDataSource = self;
//set the delegate = self. Previously declared in ViewController.h
self.tableView.tableHeaderView = searchBar; //this line add the searchBar
//on the top of tableView.
}
I decided to skip the part about the tableView cell initialization, you can find it in the downloadable source code. :)
When the tableView is ready it’s time to implement the UISearchDisplayControllerDelegate!
The delegate has many methods to control every aspect of the search, but the most important is
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
This method is called every time you insert a new character in the searchBar, you will take the searchString, perform the search through the table elements and return YES.
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[searchData removeAllObjects];
/*before starting the search is necessary to remove all elements from the
array that will contain found items */
NSArray *group;
/* in this loop I search through every element (group) (see the code on top) in
the "originalData" array, if the string match, the element will be added in a
new array called newGroup. Then, if newGroup has 1 or more elements, it will be
added in the "searchData" array. shortly, I recreated the structure of the
original array "originalData". */
for(group in originalData) //take the n group (eg. group1, group2, group3)
//in the original data
{
NSMutableArray *newGroup = [[NSMutableArray alloc] init];
NSString *element;
for(element in group) //take the n element in the group
{ //(eg. @"Napoli, @"Milan" etc.)
NSRange range = [element rangeOfString:searchString
options:NSCaseInsensitiveSearch];
if (range.length > 0) { //if the substring match
[newGroup addObject:element]; //add the element to group
}
}
if ([newGroup count] > 0) {
[searchData addObject:newGroup];
}
[newGroup release];
}
return YES;
}
That’s all! This method will perform a full-text search in all element. When the search end the tableView reload itself. See the source code to see other details.