Книга: iOS. Приемы программирования
Обсуждение
Обсуждение
Табличный вид может иметь несколько верхних и нижних колонтитулов. У каждого раздела табличного вида может быть свой верхний и нижний колонтитул, так что если у вас в табличном виде три раздела, то в нем может быть максимум три верхних и три нижних колонтитула. Вы не обязаны создавать верхние и нижние колонтитулы в каком-либо из разделов и сами решаете, сообщать или нет табличному виду, что в определенном его разделе будут верхний и нижний колонтитулы. Эти виды-колонтитулы передаются табличному виду через его делегат — если вы решите их сделать. Верхние и нижние колонтитулы становятся частью табличного вида. Это означает, что, когда содержимое таблицы прокручивается, одновременно с ним прокручиваются и колонтитулы табличных разделов. Рассмотрим примеры верхнего и нижнего колонтитулов в табличном виде (рис. 4.6).
Рис. 4.6. Нижний колонтитул в верхнем разделе и верхний колонтитул Shortcuts (Быстрый доступ) в последнем разделе табличного вида
Как видите, в верхнем разделе (там, где находятся элементы Check Spelling (Проверка правописания) и Enable Caps Lock (Зафиксировать верхний регистр)) в нижнем колонтитуле написано: Double tapping the space bar will insert a period followed by a space (Двойное нажатие клавиши пробела вставляет точку, за которой следует пробел). Это нижний колонтитул верхнего раздела рассматриваемого вида. Причина, по которой этот фрагмент находится именно в нижнем, а не в верхнем колонтитуле, в том, что он прикреплен к нижней, а не к верхней части раздела. В последнем разделе данной таблицы также есть верхний колонтитул, на котором написано Shortcuts (Быстрый доступ). Здесь, наоборот, колонтитул является верхним, а не нижним, так как он прикреплен к верхней части раздела.
Для указания высоты верхнего и нижнего колонтитулов в разделе табличного вида применяются методы, определяемые в протоколе UITableViewDataSource. Чтобы задать сам вид, который будет соответствовать верхнему/нижнему колонтитулу в разделе табличного вида, нужно использовать методы, определяемые в протоколе UITableViewDelegate.
Идем дальше. Создадим простое приложение, внутри которого будет табличный вид. Потом сделаем две метки типа UILabel, одна будет играть роль верхнего колонтитула, а другая — нижнего в единственном разделе нашего табличного вида. Этот раздел будет заполнен всего тремя ячейками. В верхнем колонтитуле мы напишем Section 1 Header (Верхний колонтитул раздела 1), а в нижнем — Section 1 Footer (Нижний колонтитул раздела 1). Начнем с файла реализации контроллера вида, где определим табличный вид:
#import «ViewController.h»
static NSString *CellIdentifier = @"CellIdentifier";
@interface ViewController () <UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) UITableView *myTableView;
@end
@implementation ViewController
После этого создадим сгруппированный табличный вид и загрузим в него три ячейки:
— (UITableViewCell *) tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier
forIndexPath: indexPath];
cell.textLabel.text = [[NSString alloc] initWithFormat:@"Cell %ld",
(long)indexPath.row];
return cell;
}
— (NSInteger) tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section{
return 3;
}
— (void)viewDidLoad{
[super viewDidLoad];
self.myTableView =
[[UITableView alloc] initWithFrame: self.view.bounds
style: UITableViewStyleGrouped];
[self.myTableView registerClass: [UITableViewCell class]
forCellReuseIdentifier: CellIdentifier];
self.myTableView.dataSource = self;
self.myTableView.delegate = self;
self.myTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
[self.view addSubview: self.myTableView];
}
И тут начинается самое интересное. Мы можем воспользоваться двумя важными методами (определяемыми в протоколе UITableViewDelegate), чтобы сделать метку и для верхнего и для нижнего колонтитула того раздела, который мы загрузили в табличный вид. Вот эти методы:
• tableView: viewForHeaderInSection: — ожидает возвращаемого значения типа UIView. Вид, возвращаемый этим методом, отобразится как верхний колонтитул раздела и будет указан в параметре viewForHeaderInSection;
• tableView: viewForFooterInSection: — ожидает возвращаемого значения типа UIView. Вид, возвращаемый этим методом, отобразится как нижний колонтитул раздела и будет указан в параметре viewForFooterInSection.
Теперь наша задача заключается в том, чтобы реализовать эти методы и вернуть экземпляр UILabel. На метке верхнего колонтитула мы укажем текст Section 1 Header (Верхний колонтитул раздела 1), а на метке нижнего — Section 1 Footer (Нижний колонтитул раздела 1), как и планировали:
— (UILabel *) newLabelWithTitle:(NSString *)paramTitle{
UILabel *label = [[UILabel alloc] initWithFrame: CGRectZero];
label.text = paramTitle;
label.backgroundColor = [UIColor clearColor];
[label sizeToFit];
return label;
}
— (UIView *) tableView:(UITableView *)tableView
viewForHeaderInSection:(NSInteger)section{
if (section == 0){
return [self newLabelWithTitle:@"Section 1 Header"];
}
return nil;
}
— (UIView *) tableView:(UITableView *)tableView
viewForFooterInSection:(NSInteger)section{
if (section == 0){
return [self newLabelWithTitle:@"Section 1 Footer"];
}
return nil;
}
Если теперь запустить приложение в эмуляторе, получится такая картинка, как на рис. 4.7.
Рис. 4.7. Метки для верхнего и нижнего колонтитулов табличного вида, выровненные неправильно
Причина такого неправильного выравнивания в том, что родительский вид не знает высоты видов-меток. Для указания высоты видов верхнего и нижнего колонтитулов следует использовать два следующих метода, определяемых в протоколе UITableViewDelegate:
• tableView: heightForHeaderInSection: — возвращаемое значение данного метода относится к типу CGFloat. Оно указывает высоту верхнего колонтитула раздела табличного вида. Индекс раздела передается в параметре heightForHeaderInSection;
• tableView: heightForFooterInSection: — возвращаемое значение данного метода относится к типу CGFloat. Оно указывает высоту нижнего колонтитула раздела табличного вида. Индекс раздела передается в параметре heightForHeaderInSection.
— (CGFloat) tableView:(UITableView *)tableView
heightForHeaderInSection:(NSInteger)section{
if (section == 0){
return 30.0f;
}
return 0.0f;
}
— (CGFloat) tableView:(UITableView *)tableView
heightForFooterInSection:(NSInteger)section{
if (section == 0){
return 30.0f;
}
return 0.0f;
}
Запустив это приложение, вы увидите, что теперь метки верхнего и нижнего колонтитулов имеют фиксированную высоту. Но в написанном нами коде все еще остается какая-то ошибка — дело в левом поле меток верхнего и нижнего колонтитулов. В этом можно убедиться, взглянув на рис. 4.8.
Рис. 4.8. Левые поля меток в верхнем и нижнем колонтитулах — неправильные
Причина заключается в том, что по умолчанию табличный вид размещает верхний и нижний колонтитулы в точке с координатой 0.0f по оси Х. Можно подумать, что эта проблема решается изменением контуров меток верхнего и нижнего колонтитулов, но, к сожалению, это мнение ошибочно. Проблема решается созданием универсального вида UIView, где и размещаются метки для верхнего и нижнего колонтитулов. Возвратите в качестве верхнего/нижнего колонтитула такой универсальный вид, но измените положение меток по оси Х в этом виде.
Теперь изменим реализацию методов tableView: viewForHeaderInSection: и tableView: viewForFooterInSection::
— (UIView *) tableView:(UITableView *)tableView
viewForHeaderInSection:(NSInteger)section{
UIView *header = nil;
if (section == 0){
UILabel *label = [self newLabelWithTitle:@"Section 1 Header"];
/* Перемещаем метку на 10 точек вправо. */
label.frame = CGRectMake(label.frame.origin.x + 10.0f,
5.0f, /* Опускаемся на 5 точек вниз
по оси y. */
label.frame.size.width,
label.frame.size.height);
/* Делаем ширину содержащего вида на 10 точек больше,
чем ширина метки, так как для метки требуется
10 дополнительных точек ширины в левом поле. */
CGRect resultFrame = CGRectMake(0.0f,
0.0f,
label.frame.size.width + 10.0f,
label.frame.size.height);
header = [[UIView alloc] initWithFrame: resultFrame];
[header addSubview: label];
}
return header;
}
— (UIView *) tableView:(UITableView *)tableView
viewForFooterInSection:(NSInteger)section{
UIView *footer = nil;
if (section == 0){
UILabel *label = [[UILabel alloc] initWithFrame: CGRectZero];
/* Перемещаем метку на 10 точек вправо. */
label.frame = CGRectMake(label.frame.origin.x + 10.0f,
5.0f, /* Опускаемся на 5 точек вниз по оси y*/
label.frame.size.width,
label.frame.size.height);
/* Делаем ширину содержащего вида на 10 точек больше,
чем ширина метки, так как для метки требуется
10 дополнительных точек ширины в левом поле. */
CGRect resultFrame = CGRectMake(0.0f,
0.0f,
label.frame.size.width + 10.0f,
label.frame.size.height);
footer = [[UIView alloc] initWithFrame: resultFrame];
[footer addSubview: label];
}
return footer;
}
Теперь, запустив приложение, вы получите примерно такой результат, как на рис. 4.9.
Рис. 4.9. В табличном виде отображаются метки верхнего и нижнего колонтитулов
Пользуясь изученными здесь методами, вы также можете размещать изображения в верхнем и нижнем колонтитулах табличных видов. Экземпляры класса UIImageView являются производными от класса UIView, поэтому вы легко можете ставить картинки в виды для изображений и возвращать их как верхние/нижние колонтитулы табличного вида. Если вы не собираетесь помещать в верхних и нижних колонтитулах табличных видов ничего, кроме текста, то можете пользоваться двумя удобными методами, определяемыми в протоколе UITableViewDataSource. Эти методы избавят вас от массы проблем. Чтобы не создавать собственные метки и не возвращать их как верхние/нижние колонтитулы табличного вида, просто пользуйтесь следующими методами:
• tableView: titleForHeaderInSection: — возвращаемое значение этого метода относится к типу NSString. Табличный вид будет автоматически помещать в метке строку, которая будет отображаться как верхний колонтитул раздела, указываемый в параметре titleForHeaderInSection;
• tableView: titleForFooterInSection: — возвращаемое значение этого метода относится к типу NSString. Табличный вид будет автоматически помещать в метке строку, которая будет отображаться как нижний колонтитул раздела, указываемый в параметре titleForFooterInSection.
Итак, чтобы упростить код приложения, избавимся от реализаций методов tableView: viewForHeaderInSection: и tableView: viewForFooterInSection:, заменив их реализациями методов tableView: titleForHeaderInSection: и tableView: titleForFooterInSection::
— (NSString *) tableView:(UITableView *)tableView
titleForHeaderInSection:(NSInteger)section{
if (section == 0){
return @"Section 1 Header";
}
return nil;
}
— (NSString *) tableView:(UITableView *)tableView
titleForFooterInSection:(NSInteger)section{
if (section == 0){
return @"Section 1 Footer";
}
return nil;
}
Теперь запустите ваше приложение в эмуляторе iPhone. Вы увидите, что табличный вид автоматически создал для верхнего колонтитула метку, выровненную по левому краю, а для нижнего колонтитула — метку, выровненную по центру, и поместил их в единственном разделе табличного вида. В iOS 7 по умолчанию верхний и нижний колонтитулы выравниваются по левому краю. В более ранних версиях iOS верхний колонтитул выравнивался по левому краю, а нижний — по центру. В любой версии выравнивание этих меток может задаваться табличным видом (рис. 4.10).
Рис. 4.10. Табличный вид, в верхнем и нижнем колонтитулах которого отображается текст