Режим редактирования таблиц
Табличные данные, представленные в элементах UITableView, нередко требуют интерактивного взаимодействия с пользователем: удаления и добавления строк во время работы программы. Для этих целей у UITableView и вспомогательных классов заготовлено несколько простых и удобных методов, которым я посвящу сегодняшний пост.
Под наши эксперименты мы возьмем один из старых проектов, который я использовал для демонстрации работы с UITableView, добавив в его интерфейс UINavigationController. Чтобы не мучать вас описанием этого процесса, предлагаю скачать его исходники и ознакомиться с ними самостоятельно.
Интерактивное удаление строк из таблицы
У нас имеется список компаний и мы бы хотели дать возможность пользователю удалить некоторые из них. Весь процесс перевода таблицы в режим редактирования состоит в использовании предопределенных и реализации некоторых виртуальных методов.
UIViewController имеет в своем арсенале предопределенный метод editButtonItem, который возвращает объект класса UIBarButtonItem, описывающий кнопку редактирования и закрепленные за ней действия, ответственные за реализацию нажатия, переключение состояний кнопки и отправку сообщений в редактируемый объект. Воспользуемся элементом Navigation Bar для размещения кнопки в интерфейсе приложения. Ее инициализацию опишем в методе awakeFromNib класса tableViewController.
self.navigationItem.leftBarButtonItem = self.editButtonItem;
Каждый раз при нажатии на кнопку “Edit” в объект UIViewController отправляется сообщение setEditing:YES animated:YES. Как обычно, его реализация остается на наших плечах и состоит всего из двух строк.
— (void)setEditing:(BOOL)editing animated:(BOOL)animate {
[super setEditing:editing animated:animate];
[listView setEditing:editing animated:animate];
}
Первой мы обеспечиваем установку внутреннего индикатора режима редактирования — переменной editing у UIViewController, а во второй переводим таблицу в режим редактирования, что приводит к появлению “красных минусов” — кнопок удаления в каждой ячейке таблицы. Окончание редактирования, инициированное повторным нажатием на кнопку, вызывает отправку все того же сообщения setEditing:animated:, но с первым параметром установленным в значение NO.
Процесс удаления ячейки проходит в два этапа: на первом вы нажимаете кнопку с минусом в выбранной строке, а на втором подтверждаете удаление нажатием на кнопку Delete.
Сам процесс удаления описывает метод tableView:commitEditingStyle:forRowAtIndexPath: протокола UITableViewDataSource.
— (void)tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[list removeObjectAtIndex:indexPath.row];
[listView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
}
}
Параметр editingStyle может принимать значение UITableViewCellEditingStyleInsert или UITableViewCellEditingStyleDelete в зависимости от действия, применяемого к ячейке. В нашем случае мы обрабатываем только операции удаления. Следующей строкой мы удаляем из массива элемент в указанной в indexPath позиции, а затем визуализуем процесс удаления вызовом метода deleteRowsAtIndexPaths:withRowAnimation:. Первый параметр содержим массив объектов NSIndexPath, несущих координаты удаляемых строк. То есть в общем виде мы можем удалить далеко не одну строчку, вдобавок красиво анимировав весь процесс, за что отвечает следующий параметр. UITableViewRowAnimation указывает тип анимации при удалении строки: это может быть сдвиг строки вправо, влево, вверх, вниз или растворение.
Реализация двух методов и добавление одной строчки в код — это все, что от вас требуется для создания редактируемой таблицы.
Но может вы хотите большего? Хотите знать…
…как все устроено?
Как я неустанно люблю повторять — интересуйтесь как устроено все, с чем вы работаете. Знание того, как приложение устроено изнутри, дает не только понимание и уверенность в своих действиях, но также предоставляет возможность создать программу, работающую и выглядящую в точности как вы хотите.
В описанном выше коде меня задело то, что его часть, ответственного за работу режима редактирования, сокрыта от любопытствующих глаз. Под мой взор попала реализация метода, отрабатывающего нажатие на кнопку Edit. Предлагаю представить как бы выглядела эта реализация, напиши мы ее вручную.
Во-первых, кнопку мы бы создали самостоятельно.
UIBarButtonItem *editButton = [[UIBarButtonItem alloc] initWithTitle:@"Edit"
style:UIBarButtonItemStyleBordered
target:self
action:@selector(editAction:)];
self.navigationItem.leftBarButtonItem = editButton;
[editButton release];
Во-вторых, в реализации метода editAction нам потребуется написать:
- отправку сообщений setEditing:animated: в UIViewController
- переключение кнопки между состоянием Edit/Done в зависимости от текущего режима редактирования
За индикацию режима редактирования отвечает переменная editing объекта UIViewController. Благодаря ей реализация первого пункта будет выглядеть следующим образом.
-(void)editAction:(id)sender {
if (self.editing) {
[self setEditing:NO animated:YES];
} else {
[self setEditing:YES animated:YES];
}
}
Чтобы изменить состояние кнопки нам потребуется всего лишь изменить подпись к ней.
-(void)editAction:(id)sender {
if (self.editing) {
[self setEditing:NO animated:YES];
self.navigationItem.leftBarButtonItem.title = @"Edit";
} else {
[self setEditing:YES animated:YES];
self.navigationItem.leftBarButtonItem.title = @"Done";
}
}
Реализация метода setEditing:animated: остается без изменений.
— (void)setEditing:(BOOL)editing animated:(BOOL)animate {
[super setEditing:editing animated:animate];
[listView setEditing:editing animated:animate];
}
Мы увидели как работает элемент изнутри и теперь в случае необходимости сможем применить полученные знания, например, для произвольной инициализации кнопки редактирования таблицы. Хотите пойти еще дальше, узнать еще больше? Ведь я еще ни слова не сказал об интерактивной вставке строк в таблицу.
Интерактивное добавление строк в таблицу
Каждая ячейка может быть представлена в трех состояниях при нахождении в режиме редактирования: отсутствие действий, разрешать удаление или разрешать вставку новой ячейки. По умолчанию все ячейки отмечаются как готовые к удалению, но их стиль можно поменять в реализации метода tableView:editingStyleForRowAtIndexPath:.
— (UITableViewCellEditingStyle)tableView:(UITableView *)tableView
editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewCellEditingStyleInsert;
}
Указанным выше образом мы отметили все ячейки готовыми к вставке. В запущенном приложении они будут отмечаться значком зеленого плюса в строке.
За обработку нажатий отвечает, как и в предыдущем примере, tableView:commitEditingStyle:forRowAtIndexPath:
— (void)tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleInsert) {
[list insertObject:@"INSERTED!" atIndex:indexPath.row];
[listView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];
}
}
В нашем примере при нажатии на “плюс” добавляется строчка с надписью “INSERTED!” перед выбранной ячейкой. Процесс добавления кардинально ничем не отличается от процедуры удаления и так же прост, как и все, с чем мы сегодня успели ознакомиться.
Напоследок хочу рассказать о способе фильтрации ячеек, который можно применять как дополнение к tableView:editingStyleForRowAtIndexPath:. Метод tableView:canEditRowAtIndexPath: разрешает или запрещает действия над ячейкой в указанной в indexPath координате.
— (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row % 2 == 0) {
return YES;
} else {
return NO;
}
}
Удачи в создании своих приложений! :)
Комментарии
Спасибо за отличный пост. Мне до сих пор таблицы кажутся в некотором виде вуду, но по-моему мы научились владеть ими на хорошом уровне. Круто.
Здóрово. Для полноты картины, наверное, надо было рассказать про перетаскивание строк.
Для начала будет достаточно, чтобы не нагружать лишней информацией. Я руководствовался тем, что перетаскивание строк не самая часто употребимая функция.
Спасибо за отличный пост, Евгений. Есть вопрос, в режиме редактирования таблицы (удаление), после нажатия на иконку появляется кнопка Delete. Есть ли какая-нибудь стандартная возможность изменить текст на этой кнопке, например на Kill? Заранее спасибо за ответ.
Форма комментирования для «Режим редактирования таблиц»