Saturday, December 22, 2012

Все о UITableView. Часть 1 http://idev.by/ios/189/

http://idev.by/ios/189/

Все о UITableView. Часть 1

АВТОР  
/  / КОММЕНТАРИИ (16)
Для пользователя очень важно, чтобы данные были представлены в удобном виде. В этой статье мы рассмотрим как создается табличное представление данных в iOS. Во многих ситуациях оно просто незаменимо. Запустите XCode и выберите пункт «Create a new XCode Project». В появившемся меню выберите шаблон «Navigation-based Application». В следующем меню необходимо указать название проекта (Product Name). В данном примере я использую «Table». Далее укажите место куда будет сохранен проект.
На данном этапе мы получили простое приложение, которое выводит на девайс пустую таблицу. В проекте у нас есть файлы RootViewController.h и RootViewController.m — это заголовочный и имплеметационный файлы для класса, который отвечает за вывод таблицы на экран девайса и обработку событий. Также присутствует файл RootViewController.xib, который отвечает за внешний вид. Открыв его можно увидеть, что вся форма состоит из одного элемента интерфейса «Table view».
Давайте наполним таблицу реальными данными. В данном примере я создам массив значений, которые будут выводиться в таблицу. Перейдем в RootViewController.h и объявим новую переменную items:
  NSMutableArray *items;
Здесь используется NSMutableArray, в который можно добавлять и удалять значения в любой момент (в отличии от NSArray, в котором значения добавляются во время инициализации)
Найдем метод viewDidLoad в имплеметационном файле RootViewController.m и добавим в него следующие строки:
  items = [[NSMutableArray alloc] init];  [items addObject:@"Яблоки"];  [items addObject:@"Апельсины"];  [items addObject:@"Груши"];
Проинициализирован наш массив, мы добавляем в него несколько элементов. Чтобы избежать утечек памяти, не забудьте добавить следующую строку в метод dealloc:
  [items release];
Для нашей таблицы необходимо указать количество ячеек, которое она будет содержать. Для этого найдем делегат numberOfRowsInSection и заменим:
  return 0;
на
  return [items count];
Тем самым укажем на то, что количество ячеек будет равняться количеству элементов в массиве items. В итоге у нас должен быть следующий код:
  - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {      return [items count];  }
Теперь перейдем к делегату cellForRowAtIndexPath. Он возвращает объект класса UITableViewCell — единичный экземпляр ячейки таблицы. Для каждой ячейки он вызывается каждый раз, когда ячейка становится видимой на экране девайса. В шаблоне уже есть исходный код, который создает и возвращает стандартную ячейку без данных. Добавим в нее данные из созданного массива. Для этого найдем комментарий:
  // Configure the cell.
После этого комментария можем свободно вставить свой код:
  cell.textLabel.text = [items objectAtIndex:indexPath.row];
Здесь все просто. У каждой ячейки есть textLabel, в который мы можем добавлять произвольный текст. В нашем примере мы добавляем текст из созданного массива items. Переменная indexPath является идентификатором, указывающим на ту ячейку, для которой был вызван делегат cellForRowAtIndexPath. У нас должен получиться следующий код:
  - (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];       }        // Configure the cell.      cell.textLabel.text = [search objectAtIndex:indexPath.row];      return cell;  }
Теперь можем смело запустить приложение. На экране должно отобразиться три элемента нашего массива.
Как вы могли заметить на iOS девайсах многие стандартные приложения используют табличное представление данных: Контакты, Настройки, YouTube… Однако сами ячейки выглядят по-разному. Мы также легко можем выбрать подходящий вид ячеек В том же делегате cellForRowAtIndexPath найдем следующую строчку:
  cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
Внешний вид ячейки определяется при ее инициализации с помощью метода initWithStyle.
  • UITableViewCellStyleDefault — Стандартный вид ячейки: только заголовок (опционально картинка слева от текста)
  • UITableViewCellStyleValue1 — Заголовок и подзаголовок (аналогично приложению Настройки, опционально картинка слева от текста)
  • UITableViewCellStyleValue2 — Заголовок и подзаголовок (аналогично приложению Контакты)
  • UITableViewCellStyleSubtitle — Заголовок и подзаголовок друг под другом (опционально картинка слева от текста)
Добавьте в проект следующие строки:
  cell.detailTextLabel.text = @"Фрукты";  cell.imageView.image = [UIImage imageNamed:@"star_color.png"];
Также необходимо добавить в проект картинку star_color.png, которая будет выводится в левой части ячейки. Для того чтобы файл (в нашем случае — картинку) добавить в проект, перетащите файл с рабочего стола (или из папки) в Project Navigator в XCode (левая панель с файлами). В появившемся окне не забудьте отметить галочку «Copy». Теперь замените:
  UITableViewCellStyleDefault
на:
  UITableViewCellStyleValue1
И запустите проект. Стиль выводимых на экран ячеек должен поменяться. Тоже самое проделайте с UITableViewCellStyleValue2 и UITableViewCellStyleSubtitle.
Табличные данные можно сгруппировать по типам или любому другому признаку. Для этого используются табличные секции. Рассмотрим пример как они работают. Создадим еще один массив с данными:
  NSMutableArray *items2;
Проинициализируем его и добавим данные:
  items2 = [[NSMutableArray alloc] init];  [items2 addObject:@"Помидоры"];  [items2 addObject:@"Огурцы"];  [items2 addObject:@"Лук"];
Не забываем почистить память в методе dealloc:
  [items2 release];
Найдем делегат numberOfSectionsInTableView. Он возвращает количество секций в таблице. Заменим:
  return 1;
на:
  return 2;
Мы указали, что в нашей таблице будет две секции. Делегат numberOfRowsInSection необходимо изменить в соответствии со следующим кодом:
  NSUInteger result;  if ( section == 0 ) {      result = [items count];  }  else {      result = [items2 count];  }  return result;
Переменная section указывает на то, для какой секции необходимо вернуть количество ячеек. Также необходимо изменить код, который отвечает за вывод данных из массива в ячейки. Найдем делегат cellForRowAtIndexPath и заменим наш написанный ранее код на:
  if (indexPath.section == 0) {      cell.textLabel.text = [items objectAtIndex:indexPath.row];      cell.detailTextLabel.text = @"Фрукты";      cell.imageView.image = [UIImage imageNamed:@"star_color.png"];  } else {      cell.textLabel.text = [items2 objectAtIndex:indexPath.row];      cell.detailTextLabel.text = @"Овощи";      cell.imageView.image = [UIImage imageNamed:@"star_color.png"];  }
Здесь все понятно — в зависимости от секции мы используем соответствующий массив с данными. Для того, чтобы на экране мы могли увидеть разделение элементов на секции необходимо сделать еще одно действие. Добавим в любое свободное место следующий код:
  - (NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {      NSString *result  =nil;      if (section == 0) {          result = @"Фрукты";      } else {          result = @"Овощи";      }      return result;  }
В этом делегате мы задаем название каждой секции. В целом код похож на код делегата numberOfRowsInSection. Теперь можем запустить наш проект и увидеть что данные разделены на две независимые секции. Помимо стиля ячеек мы можем задать общий стиль таблицы. Стиль, который вы видите на экране называется «Plain». Для того, чтобы сделать разделение секций более явным можно использовать стиль «Grouped». Для этого откройте RootViewController.xib и перейдите на нашу таблицу TableView. Выберите пункт меню View -> Utilities -> Attributes Inspector (⌥⌘4) и найдите строку «Style». По умолчанию указан стиль «Plain». Укажите «Grouped» и запустите проект снова.
Еще одна интересная возможность таблиц в iOS — это создание индекса. Пример использования индекса можно увидеть в приложении Контакты, когда на экран выводятся все контакты. Полоска с алфавитом справа от ячеек называется индексом. В своих таблицах вы можете использовать любые значения, не обязательно это будет алфавит. Давайте посмотрим как это реализуется. Добавим в наш код следующие строки:
  - (NSArray *) sectionIndexTitlesForTableView: (UITableView *) tableView {      NSMutableArray *values = [[NSMutableArray alloc] init];      [values addObject:@"Фрукты"];      [values addObject:@"Овощи"];      return values;  }
За создание индекса в таблице отвечает делегат sectionIndexTitlesForTableView. Здесь вы должны вернуть массив значений индексов. В нашем примере я просто продублировал название секций. запустите проект и вы должны увидеть индекс в правой части экрана. И самое главное — созданный индекс полностью рабочий. Нажатие на любое из его значений автоматически перенесет вас на нужную секцию.
Продолжение тут
Исходники source-part1

Похожие статьи

0
Оцените пожалуйста статью. Ваш голос важен автору!

  1. 01.09.2011

    Дима

    thank you site admin!
    excellent article very helpful))
      
  2. 21.09.2011

    Vasilii

    Отличная статья, все четко и понятно. Только у меня возникла одна проблема, не могу понять в чем дело: если не создавать индекс, то приложение вылетает в 95% случаев, но иногда грузится. А если я создаю индекс (индекс представляет собой большинство букв русского алфавита), то все отлично работает. Есть подозрение, что это может быть связано с большим количеством данных, которые находятся в UITableView (около 2000 строк), но это всего лишь подозрение…
      
  3. 21.09.2011

    Vasilii

    Привожу пример кода:
      @implementation FirstScreen    - (void)viewDidLoad  {      MyClass *data = [MyData sharedMySingleton];      arrayData = [data getDataFromDatabase];        russianLettersAndNumbers = [NSArray arrayWithObjects: @"А", @"Б", @"В", @"Г", @"Д", @"Е", @"Ж", @"З", @"И", @"К", @"Л", @"М", @"Н", @"О", @"П", @"Р", @"С", @"Т", @"У", @"Ф", @"Х", @"Ц", @"Ч", @"Ш", @"Щ", @"Э", @"Ю", @"Я", nil];        [tableViewResult reloadData];        [super viewDidLoad];      // Do any additional setup after loading the view from its nib.    }    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {      return [russianLettersAndNumbers count];  }    // Customize the number of rows in the table view.  - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {        MyClass *data = [MyClass sharedMySingleton];      NSString *letterOrNumber = [russianLettersAndNumbers objectAtIndex:section];      return [[data getDataByPatternOrByFirstLetter:YES patternOfFirstLetter:letterOrNumber] count];  }    // Customize the appearance of table view cells.  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {        static NSString *CellIdentifier = @"Cell";        UITableViewCell *cell = [tableViewResult dequeueReusableCellWithIdentifier:CellIdentifier];      if (cell == nil) {          cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: CellIdentifier] autorelease];        }        ScrollingLabel *scrollingLabel = nil;      int countOfScrollingLabel = 0;      for (UIView *subview in [cell subviews]) {          if ([subview isKindOfClass:[ScrollingLabel class]]) {              countOfScrollingLabel++;              scrollingLabel = (ScrollingLabel *)subview;          }      }      if (countOfScrollingLabel == 0)      {          scrollingLabel = [[ScrollingLabel alloc] initWithFrame:CGRectMake(0, 0, 150, 40)];          [cell addSubview:scrollingLabel];          [scrollingLabel release];      }        MyClass *data = [MyClass sharedMySingleton];      NSString *letterOrNumber = [russianLettersAndNumbers objectAtIndex:indexPath.section];      NSMutableArray *subArray = [data getDataByPatternOrByFirstLetter:YES patternOfFirstLetter:letterOrNumber];        scrollingLabel.text = [subArray objectAtIndex:indexPath.row];        return cell;  }    - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {      return [russianLettersAndNumbers objectAtIndex:section];  }    - (NSArray *) sectionIndexTitlesForTableView: (UITableView *) tableView {      return russianLettersAndNumbers;  }    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {        for (UIView* subview in [tableView cellForRowAtIndexPath:indexPath].subviews)      {          if ([subview isKindOfClass:[ScrollingLabel class]])              [(ScrollingLabel *)subview startAnimate];      }  }      @end      // @interface ScrollingLabel : UIScrollView
    На самом деле, мне и нужно, чтобы создавался индекс из русских букв. Меня просто интересует, почему без него приложение вылетает?
      
  4. 22.09.2011

    Vasilii

    Что мне написать вам на почту? Мой почтовый ящик ведь прикреплен к комментариям…
      
  5. 05.10.2011

    Женя-Пеня

    russianLettersAndNumbers создание авторелизнутого объекта во вью дид лоад… причём 2 раза…. меня смутило сразу… может там в чём то ещё дело… вникать лень но чую я что этот russianLettersAndNumbers удалится очень быстро)))
      
  6. 05.01.2012

    intruders

    Найдем метод viewDidLoad в имплеметационном файле RootViewController.m и добавим в него следующие строки:»
    items = [[NSMutableArray alloc] init];"

    Чтобы избежать утечек памяти, не забудьте добавить следующую строку в метод dealloc:
    [items release];
    Тут как раз утечка памяти будет, если view будет выгружаться/загружаться несколько раз (система может так поступить если памяти мало). Релизить в данном случае надо в методе viewDidUnload.
      
  7. 14.04.2012

    ivandeft

    Дайте исходник.
    По ссылке выдает ошибку 404 — ресурс не найден.
    А на последнем XCode нет NavigationBased App((
      
  8. 10.12.2012

    crazy_blu

    Возник вопрос. Попробовал повторить все «с нуля» на XCode 4.5 под IOS 5.1
    Указанного темплейта нет, пришлось воспроизводить все «пошагово»
    В итоге Ваш пример работает, а мой изначально содержимого таблицы показывать не хочет. Если «повернуть» эмулятор, то перерисовывает все корректно, но по старту рисунка нет. Попытки в viewDidLoad вызвать [_table reloadData] к успеху не приводят. В чем могут быть проблемы?
      

No comments:

Post a Comment