23 сентября 2010 г.

"Привязываем" UISearchBar к UITableView

У меня возникла задача использовать фильтр к большому списку однотипных элементов (проще говоря поиск). Раньше я решал такую задачу кидая на UINavigationBar элемент UITextField и обрабатывал его события, но выглядело это очень некрасиво. UISearchBar хоть и занимает дополнительное место на экране, но выглядит приятно и вписывается в интерфейс, хотя при редактировании в UISearchBar можно скрывать UINavigationBar для освобождения пространства на экране.

Как я реализовывал.
Есть класс наследник от UIViewController в котором находятся визуальные компоненты (UISearchBar и UITableView). Так-же этот класс содержит два массива: массив со всеми элементами которые могут присутствовать в списке, второй с элементами которые удовлетворяют условиям поиска. Изначально массивы равны. Второй массив необходимо отображать в UITableView и применять к нему фильтр при изменении текста в UISearchBar. Просто?

Начнем с функции поиска, в моем случае я у меня строковые массивы (itemsList - со всеми элементами, searched - с элементами которые удовлетворяют условию из UISearchBar). Единственным параметр функции - строка из UISearchBar:

  1. - (void) search:(NSString *) matchString
  2. {
  3.   NSString *upString = [matchString uppercaseString];
  4.   if (searched)
  5.     [searched release];
  6.   searched = [[NSMutableArray alloc] init];
  7.   for (NSString *line in itemsList)
  8.   {
  9.     if ([matchString length] == 0)
  10.     {
  11.       [searched addObject:line];
  12.       continue;
  13.     }
  14.     NSRange range = [[line uppercaseString] rangeOfString:upString];
  15.     if (range.location != NSNotFound)
  16.       [searched addObject:line];
  17.   }
  18.   [tv reloadData]; // UITableView
  19. }


я тут не боролся за оптимальность поиска. Можно было б не пересоздавать при каждом вызове массив searched, а так-же учитывать предыдущий поиск.

Функция search: должна вызываться при каждом изменении в UISearchBar, для которого нужно определить делегат с методом searchBar:textDidChange:

  1. - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
  2. {
  3.   [self search:searchText];
  4. }


так-же для иницилизации массива searched метод search: нужно вызвать при загрузке вью конттроллера, например в методе loadView

  1. - (void)loadView
  2. {
  3.   [self search:@""];
  4. }


и осталось отобразить массив searched в UITableView

  1. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  2. {
  3.   UITableViewCell *rv = nil;
  4.   NSString *cellID = @"cell_ID";
  5.   rv = [tableView dequeueReusableCellWithIdentifier:cellID];
  6.   if (rv==nil)
  7.   {
  8.     rv = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:cellID] autorelease];
  9.   }
  10.   rv.textLabel.text = [searched objectAtIndex:indexPath.row];
  11.   return rv;
  12. }


В статье не описано, что нужно обрабатывать появление клавиатуры, а так-же можно скрывать UINavigationBar при фокусе на UISearchBar, что есть в примере.

1 комментарий: