Показаны сообщения с ярлыком UITableView. Показать все сообщения
Показаны сообщения с ярлыком UITableView. Показать все сообщения

28 ноября 2010 г.

Кастомные заголовки и подписи в секциях UITableView

Иногда необходимо что б в заголовке секции таблицы UITableView отображался не только текст, но и картинка, или может даже кнопка. Компонента UITableView позволяет не только задавать текстовую строку как заголовок к каждой секции но и устанавливать свое UIView как элемент заголовка.

UITableView поддерживает отсылку событий по двум протоколам UITableViewDataSource и UITableViewDelegate. Первый отвечает за получение данных которые отображаются в компоненте, второй за их внешний вид. В протоколе UITableViewDataSource есть методы – tableView:titleForHeaderInSection: и – tableView:titleForFooterInSection: которые должны возвращать строки заголовка и подписи для каждой секции в таблице. Но в протоколе UITableViewDelegate можно реализовать методы – tableView:viewForHeaderInSection: и – tableView:heightForHeaderInSection: для установки вашего вью на заголовок секции (методы – tableView:viewForFooterInSection: и – tableView:heightForFooterInSection: для подписи секции)

Реализуем простой пример использования (скачать можно отсюда)

У нас есть UIViewController на котором находится UITableView. Создаем вью которое будем использовать как заголовок секции таблицы.

  1.   CGRect rct;
  2.   headerView = [[UIView alloc] initWithFrame:CGRectZero];
  3.   UIImage *img = [UIImage imageNamed:@"apple.png"];
  4.   UIImageView *tmpImgView = [[UIImageView alloc] initWithImage:img];
  5.   rct = CGRectMake(screenRect.size.width*.05, 0.0, img.size.width, img.size.height);
  6.   tmpImgView.frame = rct;
  7.   [headerView addSubview:tmpImgView];
  8.   rct.origin.x = 0.0;
  9.   rct.size = CGSizeMake(screenRect.size.width, rct.size.height);
  10.   headerView.frame = rct;
  11.   [tmpImgView release];


тут headerView - имеет тип UIView, его то мы и будем отображать в таблице.

А теперь опишем функции отображение этого вью как заголовка первой секции таблицы:

  1. - (UIView *) tableView:(UITableView *) tableView viewForHeaderInSection:(NSInteger) section
  2. {
  3.   if (section==0)
  4.   {
  5.     return headerView;
  6.   }
  7.   return nil;
  8. }
  9. - (CGFloat) tableView:(UITableView *) tableView heightForHeaderInSection:(NSInteger) section
  10. {
  11.   if (section==0)
  12.   {
  13.     return headerView.frame.size.height;
  14.   }
  15.   return 0.0;
  16. }


В первой функции мы возвращаем вью которое должно отображаться в таблице, во второй - высоту этого вью.

Так-же в компоненте UITableView можно использовать свойства tableHeaderView  и tableFooterView  для задания вью как заголовка и подписи всей таблицы.

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, что есть в примере.