Adding UISearchBar programmatically to UITableView
Solution 1
Set the frame for the UISearchBar:
// Change the position according to your requirements
self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 70, 320, 44)];
If your view is a subclass of UITableViewController
, change it to UIViewController
.
In your nib file, create a view and drag your tableView under that view and change the reference class for that view to your
UIViewController
.Create an
IBOutlet
ofUITableView * myTableView
and connect it to your nib file. you just need to change in your VC file for example self to[self.myTableView reloadData];
Now you can adjust the tableView
and search bar in the nib itself.
UISearchDisplay
controller has its own UITableView
that displays the results of a search of data managed by another view controller. Here the searchDisplaycontroller
combines the search bar and tableview to show the result data in the tableview so it won't require a separate tableview.
Solution 2
To add a UISearchBar to a UITableView there are these things to do:
- Declare and initialize UISearchBar
- Declare and initialize the UISearchDisplayController
- Add the searchBar to the tableView
- Implement the UISearchDisplayController delegate
- In the header file I declare my searchBar, searchDisplayController and the arrays that contain the data to display.
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.
Download source file (Link UPDATED! (04.01.2016) )
Solution 3
Implement - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
. This will solve the problem of section Label covering the headerView
Solution 4
in swift:
let searchController = UISearchController(searchResultsController: nil)
let topConstraint = NSLayoutConstraint(item: searchController.searchBar, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 40)
let leftConstraint = NSLayoutConstraint(item: searchController.searchBar, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 0)
let rightConstraint = NSLayoutConstraint(item: searchController.searchBar, attribute: NSLayoutAttribute.Right, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 0)
let heightConstraint = NSLayoutConstraint(item: searchController.searchBar, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 44)
searchController.searchBar.translatesAutoresizingMaskIntoConstraints = false
searchController.searchBar.addConstraint(heightConstraint)
searchController.searchBar.placeholder = "Search Here"
searchController.searchResultsUpdater = self
searchController.searchBar.delegate = self
self.view.addSubview(searchController.searchBar)
self.view.addConstraints([topConstraint, leftConstraint, rightConstraint])
add delegate:
class ViewController: UIViewController, UISearchBarDelegate
now add delegate method to reload table view:
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
//add your custome code here after search a string
tableView.reloadData()
}
func searchBarTextDidEndEditing(searchBar: UISearchBar) {
//add your custome code here after finishing search
tableView.reloadData()
}
Gary Hedren
Updated on December 04, 2020Comments
-
Gary Hedren over 3 years
I am attempting to add a
UISearchBar
(with its corresponding search logic) but there is a problem: I am using theUITableViewController
subclass's automatically generatedUITableView
instead of a separatenib
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 defaultUITableView
and transfer to a customUITableView
nib file so that I can easily add theUISearchbar
?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 myviewDidLoad
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];
-
Praveen-K almost 13 yearshmm so this fix the problem? that is why i said to you Change the position according to your requirement. i updated my answer as well :)
-
Julien almost 13 yearsSorry I wrote the comment to quickly. What I wanted to say is that (0, 0, 320, 44) is the only possible frame, as the table header view is always positioned top left and takes full width, and the UISearchBar is always 44px height. You could set whatever you want, it will have this frame
-
Julien almost 13 yearsYou add an unnecessary process, I've reproduced his issue and this works : UISearchBar *testbar = [[UISearchBar alloc] initWithFrame:CGRectMake(0,170,320,44)]; [[self tableView] setTableHeaderView:testbar];
-
Praveen-K almost 13 yearsIn my first answer i just told you to change the frame then you said "table header view is always positioned top left and takes full width, and the UISearchBar is always 44px height." so i gave you second option. i have not said in my answer that you should remove [[self tableView] setTableHeaderView:testbar];
-
Gary Hedren almost 13 yearsHi, thanks for the help, it definitely appears in the right location now (though I'm always weary of using CGRectMakes over delegate methods if I can. Anyway, I did some looking around and it appears that UITableView has a built-in UISearchDisplay controller, so I should just be able to tap into that and forget about Interface Builder, right?
-
Praveen-K almost 13 years@Gary as you said "it appears that UITableView has a built-in UISearchDisplay controller" is wrong. UISearchDisplay controller has own search tableView that displays the results of a search of data managed by another view controller. Here the searchDisplaycontroller combines the searchbar and tableview which showing the result data in the tableview so it won't required separate tableview. Sorry i did not mention this description in my answer to make it more clear, how it works.. :)
-
Shmidt almost 11 years@Praveen-K This answer works great with search that has no searchDisplayController. Because if it has, searchbar has a gray background. Do you know any workaround to remove that background?
-
Syed Asad Ali over 9 yearsIn viewDidLoad I have to include this line also: searchDisplayController.searchResultsDataSource = self; otherwise tableView is not reload by shouldReloadTableForSearchString
-
Paulo Rodrigues about 9 yearsDownload link broken.
-
Navin Leon almost 9 yearsCan you provide the active link to download the code?
-
minux almost 9 yearsSorry but I lost the sample code and the web site is no longer online :(
-
minux almost 9 yearsUPDATE: I found sample code in my old hardisk! :) Here it is: aurealab.net/minux/UISearchBarSample.zip
-
Admin almost 9 yearsThis way is deprecated in favor of
UISearchController
-
tokentoken over 7 yearsUISearchDisplayController is depricated from iOS8, so now we have to use UISearchController. stackoverflow.com/questions/33711358/…