iOS. Приемы программирования — страница 34 из 124

Постановка задачи

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

Решение

Реализуйте следующие три метода протокола UITableViewDelegate в объекте-делегате вашего табличного вида.

• tableView: shouldShowMenuForRowAtIndexPath: — возвращаемое значение данного вида относится к типу BOOL. Если вернуть от этого метода значение YES, то система iOS отобразит для ячейки табличного вида контекстное меню. Индекс этой ячейки будет передан вам в параметре shouldShowMenuForRowAtIndexPath.

• tableView: canPerformAction: forRowAtIndexPath: withSender: — возвращаемое значение данного метода также относится к типу BOOL. Как только вы позволите iOS отображать контекстное меню для ячейки табличного вида, iOS вызовет этот метод несколько раз и сообщит вам селектор действия. После этого вы сможете решить, следует ли отображать это действие в командах контекстного меню. Итак, если iOS спрашивает вас, хотите ли вы отобразить для пользователя меню Copy (Копировать), то рассматриваемый метод будет вызван в объекте-делегате вашего табличного вида и параметр canPerformAction данного метода будет равен @selector(copy:). Подробнее этот вопрос рассматривается в подразделе «Обсуждение» данного раздела.

• tableView: performAction: forRowAtIndexPath: withSender: — как только вы разрешите отобразить определенное действие в списке вариантов контекстного меню ячейки табличного вида, возникает такая ситуация: когда пользователь выбирает это действие в меню, данный метод вызывается в объекте-делегате вашего табличного вида. Здесь нужно сделать все необходимое, чтобы удовлетворить пользовательский запрос. Например, если пользователь выбрал меню Copy (Копировать), то вы должны применить буфер обмена (Pasteboard), куда помещается содержимое из ячейки табличного вида.

Обсуждение

Табличный вид может дать системе iOS ответ «да» или «нет», позволив или не позволив отобразить доступные системные элементы меню для данной табличной ячейки. iOS пытается вывести контекстное меню для табличной ячейки, когда пользователь удерживает эту ячейку пальцем в течение определенного временного промежутка — обычно примерно 1 с. Затем iOS пытается узнать табличный вид, одна из ячеек которого инициировала появление контекстного меню на экране. Если табличный вид ответит, то iOS сообщит ему, какие команды можно отобразить в контекстном меню, а табличный вид сможет утвердительно или отрицательно отреагировать на каждый из этих вариантов. Например, если доступны пять вариантов (элементов) и табличный вид отвечает «да» на два из них, то будут отображены только два этих элемента.

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

Предлагаю сначала рассмотреть, какие действия доступны в контекстном меню ячейки табличного вида. Поэтому создадим табличный вид и отобразим в нем несколько ячеек:


— (NSInteger) tableView:(UITableView *)tableView

numberOfRowsInSection:(NSInteger)section{

return 3;

}


— (UITableViewCell *) tableView:(UITableView *)tableView

cellForRowAtIndexPath:(NSIndexPath *)indexPath{


UITableViewCell *cell = nil;


cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier

forIndexPath: indexPath];


cell.textLabel.text = [[NSString alloc]

initWithFormat:@"Section %ld Cell %ld",

(long)indexPath.section,

(long)indexPath.row];


return cell;


}


— (void)viewDidLoad{

[super viewDidLoad];


self.myTableView = [[UITableView alloc]

initWithFrame: self.view.bounds

style: UITableViewStylePlain];

[self.myTableView registerClass: [UITableViewCell class]

forCellReuseIdentifier: CellIdentifier];


self.myTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth |

UIViewAutoresizingFlexibleHeight;


self.myTableView.dataSource = self;

self.myTableView.delegate = self;


[self.view addSubview: self.myTableView];


}


Теперь реализуем три упомянутых ранее метода, определенных в протоколе UITableViewDelegate, и просто преобразуем доступные действия (типа SEL) в строку, после чего выведем доступные результаты на консоль:


— (BOOL) tableView:(UITableView *)tableView

shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath{


/* Разрешаем отображение контекстного меню для каждой ячейки */

return YES;


}


— (BOOL) tableView:(UITableView *)tableView

canPerformAction:(SEL)action

forRowAtIndexPath:(NSIndexPath *)indexPath

withSender:(id)sender{


NSLog(@"%@", NSStringFromSelector(action));


/* Пока разрешим любые действия. */

return YES;

}


— (void) tableView:(UITableView *)tableView

performAction:(SEL)action

forRowAtIndexPath:(NSIndexPath *)indexPath

withSender:(id)sender{


/* Пока оставим пустым. */


}


А теперь запустим приложение в эмуляторе или на устройстве. После этого мы увидим, что в табличный вид загружены три ячейки. Удерживайте на ячейке палец (если работаете с устройством) или указатель мыши (если с эмулятором) и смотрите, какая информация появляется в окне консоли:


cut:

copy:

select:

selectAll:

paste:

delete:

_promptForReplace:

_showTextStyleOptions:

_define:

_addShortcut:

_accessibilitySpeak:

_accessibilitySpeakLanguageSelection:

_accessibilityPauseSpeaking:

makeTextWritingDirectionRightToLeft:

makeTextWritingDirectionLeftToRight:


Все это действия, которые система iOS позволяет вывести на экран для пользователя, если такие действия вам понадобятся. Допустим, вы хотите разрешить пользователям операцию копирования (Copy). Для этого перед отображением команды просто найдите в методе tableView: canPerformAction: forRowAtIndexPath: withSender:, на какое действие запрашивает у вас разрешение система iOS, а потом верните значение YES или NO:


— (BOOL) tableView:(UITableView *)tableView

canPerformAction:(SEL)action

forRowAtIndexPath:(NSIndexPath *)indexPath

withSender:(id)sender{


if (action == @selector(copy:)){

return YES;

}


return NO;

}


На следующем этапе перехватываем информацию о том, какой именно элемент был выбран пользователем в контекстном меню. В зависимости от того, что выяснится, мы можем совершить нужное действие. Например, если пользователь выберет в контекстном меню команду Copy (Копировать) (рис. 4.11), мы воспользуемся UIPasteBoard, чтобы скопировать эту ячейку в компоновочный буфер и иметь возможность применять ее позже:


— (void) tableView:(UITableView *)tableView

performAction:(SEL)action

forRowAtIndexPath:(NSIndexPath *)indexPath

withSender:(id)sender{


if (action == @selector(copy:)){


UITableViewCell *cell = [tableView cellForRowAtIndexPath: indexPath];

UIPasteboard *pasteBoard = [UIPasteboard generalPasteboard];

[pasteBoard setString: cell.textLabel.text];


}


}


Рис. 4.11. Команда Copy (Копировать), отображенная в контекстном меню ячейки табличного вида

4.7. Перемещение ячеек и разделов в табличных видах