よくTwitterアプリのタイムライン検索などで使われている検索バーがありますが、けっこうサクッと追加できます。
UISearchBar を使う
検索バーにフォーカスすると自動的にナビゲーションバーが隠れて [cancel] ボタンが表示されます。
更に、文字を入力していくとテーブルの中身が絞り込まれていく仕組みが用意されています。

どうやって絞り込んでいくかは、- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope の中身をごにょごにょすればいい。
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
// ごにょごにょ
}
UITableViewController に UISearchBar を追加
以下のソースは余分なものを削っています。
RootViewController.h
@interface RootViewController : UITableViewController <UISearchDisplayDelegate, UISearchBarDelegate> {
NSArray *_items;
NSMutableArray *_filteredListContent;
}
@end
RootViewController.m
#import "RootViewController.h"
@implementation RootViewController
#pragma mark - View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"Products";
// InterfaceBuilderを使わずに view を作成
self.view = [[UIView alloc] initWithFrame:CGRectZero];
[self.view release];
// InterfaceBuilderを使わずに tableView を作成
self.tableView = [[UITableView alloc] initWithFrame:CGRectZero];
self.tableView.separatorColor = [UIColor colorWithRed:0.91 green:0.91 blue:0.91 alpha:1.0];
[self.tableView release];
// InterfaceBuilderを使わずに UISearchBar を追加
UISearchBar *searchBar;
searchBar = [[[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 44.0f)] autorelease];
searchBar.showsCancelButton = YES;
searchBar.tintColor = [UIColor lightGrayColor];
searchBar.delegate = self;
searchBar.placeholder = @"検索ワードを入力してください";
searchBar.showsCancelButton = NO;
[searchBar sizeToFit];
self.tableView.tableHeaderView = searchBar;
UISearchDisplayController *searchDisplayController;
searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
searchDisplayController.delegate = self;
searchDisplayController.searchResultsDelegate = self;
searchDisplayController.searchResultsDataSource = self;
// 配列を生成
_items = [[NSArray alloc] initWithObjects:@"iPhone", @"iPod", @"iPod touch", @"iMac", @"Mac Pro", @"iBook", @"MacBook", @"MacBook Pro", @"PowerBook", nil];
_filteredListContent = [[NSMutableArray arrayWithCapacity:[_items count]] retain];
[self.tableView reloadData];
self.tableView.scrollEnabled = YES;
}
- (void)viewDidUnload {
_filteredListContent = nil;
[super viewDidUnload];
}
- (void)dealloc {
[_items release];
[_filteredListContent release];
[super dealloc];
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [_filteredListContent count];
}
return [_items count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
NSString *label;
if (tableView == self.searchDisplayController.searchResultsTableView) {
label = [_filteredListContent objectAtIndex:indexPath.row];
} else {
label = [_items objectAtIndex:indexPath.row];
}
cell.textLabel.text = label;
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIViewController *detailsViewController = [[UIViewController alloc] init];
NSString *label;
if (tableView == self.searchDisplayController.searchResultsTableView) {
label = [_filteredListContent objectAtIndex:indexPath.row];
} else {
label = [_items objectAtIndex:indexPath.row];
}
detailsViewController.title = label;
[[self navigationController] pushViewController:detailsViewController animated:YES];
[detailsViewController release];
}
#pragma mark - Content Filtering
- (void)filterContentForSearchText:(NSString *)searchText scope:(NSString *)scope {
[_filteredListContent removeAllObjects];
for (NSString *label in _items) {
NSComparisonResult result = [label compare:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [searchText length])];
if (result == NSOrderedSame) {
[_filteredListContent addObject:label];
}
}
}
#pragma mark - UISearchDisplayController Delegate Methods
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self filterContentForSearchText:searchString scope:[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
return YES;
}
@end
ソースコードは、iOS Developer Library にあったものを参考にしました。
最後に
苦労したのは、UISearchDisplayController を生成するところ。
UIViewController にあらかじめ用意されている self.searchDisplayController が readonly だったので、それを直接書き換えることができず…。
どうやら、UISearchDisplayController を初期化メソッドで生成すれば自動的に認識してくれるらしいです。
