UISearchBar Search table row with text, subtext and image
I've noticed that in order to do a search of a table, a copy of that data must be inserted to a search array.
E.g.
//Initialize the array.
listOfItems = [[NSMutableArray alloc] init];
NSArray *countriesToLiveInArray = [NSArray arrayWithObjects:@"Iceland", @"Greenland", @"Switzerland", @"Norway", @"New Zealand", @"Greece", @"Rome", @"Ireland", nil];
NSDictionary *countriesToLiveInDict = [NSDictionary dictionaryWithObject:countriesToLiveInArray forKey:@"Countries"];
NSArray *countries开发者_JS百科LivedInArray = [NSArray arrayWithObjects:@"India", @"U.S.A", nil];
NSDictionary *countriesLivedInDict = [NSDictionary dictionaryWithObject:countriesLivedInArray forKey:@"Countries"];
[listOfItems addObject:countriesToLiveInDict];
[listOfItems addObject:countriesLivedInDict];
//Initialize the copy array.
copyListOfItems = [[NSMutableArray alloc] init];
So what is searched is the objects that are stored in the copied array.
My Question is, how do I search Cell rows with text, subtext and image in that particular cell.
(1)
There isn't really any such thing as searching a table. What happens when the user enters text in a UISearchBar is totally up to you - you can make that operation mean anything you like. All you have to do is function as the delegate-and-data-source for the results table and form the results table in response to the standard Three Big Questions that form the basis for any table ("how many sections have you? how many rows in this section? what's the cell for this row?") in any way you like. The results table does often look like a reduced version of the original table, but this is not at all required! It can be any table you want it to be.
(2)
Don't confuse Model with View. The table is just a view. Your data is Model. It is the Model, your data that is the basis of the original table, that you are going to be searching. So when the user types in your UISearchBar and you start searching, you want to form a new Model that will be the basis of the results table. How you form it is completely up to you. Typically you'll want to filter the original model so that the only stuff left in your results model is stuff that counts as a valid result. You could do this by walking the whole original model, putting everything that matches the search criterial into the new model. Or, if the original model is an array, you could use one of the filteredArray methods to help you. The most flexible way is to form a predicate with a block, as in this example from my book:
NSPredicate* p = [NSPredicate predicateWithBlock:
^BOOL(id obj, NSDictionary *d) {
NSString* s = obj;
NSStringCompareOptions options = NSCaseInsensitiveSearch;
return ([s rangeOfString:sbc.searchBar.text
options:options].location != NSNotFound);
}];
self.filteredStates = [states filteredArrayUsingPredicate:p];
In that example, s
(one item of the array) is a string each time, and I'm looking to see whether the user's search term occurs in that string. But if you had a dictionary or other structure holding both a title and a subtitle and info about an image, you could examine that dictionary in any way you like. It's just a matter of returning YES or NO according to whether this array item passes the test based on the search term, on whatever definition you attach to the notion of passing the test.
(3)
The big question remaining is when to form the results model. I usually start by making the results model identical to the original model in response to searchDisplayControllerWillBeginSearch
, because otherwise the results table will say No Results while the user is typing. (That is probably why you think the first thing to do is copy the original model.) Then, I can either do the actual filtering in response to searchBarSearchButtonClicked
(the user is done typing and has tapped Search), or if the model is small enough, I can filter it afresh after every letter the user types, in response to searchBar:textDidChange
(the user has typed a letter in the search bar).
There are a few steps involved. Note that the code below is just an example that I'm typing in by hand now, so it probably won't compile, it's just to give you an idea.
1) Ensure that you have an array containing all the cell values.
2) Create a copy of that array, and use that copy as the data source when returning cells in your table delegate methods.
3) Set yourself up as delegate for the UISearchBar, and respond to its events:
- (void)searchBarButtonClicked(UISearchBar *)searchBar {
[self doSearch:searchBar.text];
}
- (void)searchBar(UISearchBar *)searchBar textDidChange:(NSString *)searchTerm {
if (searchTerm.length == 0) {
[self resetSearch];
[table reloadData];
}
else
[self doSearch:searchTerm];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
searchBar.text = @"";
[self resetSearch];
[table reloadData];
[searchBar resignFirstResponder];
}
4) Create the other methods
The resetSearch
method just needs to copy your full data array to the data source array used by your table delegates:
- (void)resetSearch {
self.tableSourceArray = [self.dataSourceArray copy]; // Or write a deep copy if you want to.
}
Whereas when searching, we need to filter the datasource
array. You may be able to create something more efficient - this is just an example.
- (void)doSearch:(NSString *)searchTerm {
NSMutableArray *filtered = [[NSMutableArray alloc] init];
for (NSString *item in self.self.dataSourceArray) {
if ([item rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location != NSNotFound])
[filtered addObject:[item copy]];
}
self.tableSourceArray = filtered;
}
And that should be it!
Tim
精彩评论