Как получить выбранную ячейку представления таблицы в пользовательском действии в UIMenuController

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

Я зарегистрировал UILongPressGestureRecognizer в методе viewDidLoad в моем подклассе UITableViewController и добавил пользовательский элемент с помощью @selector(handleMyAction).

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self.refreshControl addTarget:self action:@selector(refreshView:) forControlEvents:UIControlEventValueChanged];

    UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
    longPressGesture.minimumPressDuration = .5;
    longPressGesture.delegate = self;
    [self.tableView addGestureRecognizer:longPressGesture];
}

-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
    if(gestureRecognizer.state == UIGestureRecognizerStateBegan)
    {
        CGPoint point = [gestureRecognizer locationInView:self.tableView];
        NSIndexPath * indexPath = [self.tableView indexPathForRowAtPoint:point];
        if(indexPath == nil) return ;
        UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];

        UIMenuItem *it = [[UIMenuItem alloc] initWithTitle:@"My Action on this cell" action:@selector(handleMyAction:)];
        UIMenuController *menu = [UIMenuController sharedMenuController];
        [menu setMenuItems:[NSArray arrayWithObjects:it, nil]];
        [menu setTargetRect:cell.frame inView:cell.superview];
        [menu setMenuVisible:YES animated:YES];
        [self becomeFirstResponder];
    }
}

Я также переопределяю

- (BOOL)canBecomeFirstResponder{
    return YES;
}

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

- (void)handleMyAction:(id)sender
{
    NSLog(@"Action triggered, however need some way to refer the tapped cell");
}

Поскольку единственная информация, которую я могу получить в этом методе, - это отправитель, который является самим UIMenuController, но я понятия не имею, как получить ячейку, в которой сработало меню, поэтому я могу выполнить дальнейшие действия относительно самой ячейки.

Может ли кто-нибудь помочь мне в этом?

Спасибо. Хай


person Hai    schedule 09.01.2014    source источник


Ответы (3)


Ну, вы в настоящее время добавляете UIGestureRecognizer к самому табличному представлению. Почему бы вместо этого не добавить его в каждую ячейку (в cellForRowAtIndexPath, когда они настроены)?

person valheru    schedule 10.01.2014
comment
Вы имеете в виду в cellForRowAtIndexPath, верно? Даже если я это сделаю, меню будет запущено в ячейке, и будет вызван обработчик моего действия handleMyAction, если я выберу My Action для этой записи ячейки во всплывающем меню, однако, как я могу получить доступ к ячейке в функции handleMyAction, потому что единственным параметром этой функции является отправитель, это UIMenuController. - person Hai; 10.01.2014
comment
На самом деле, если вы установите распознаватель жестов в ячейку, отправителем будет сам распознаватель жестов, аgestRecognizer.view — ячейка. - person valheru; 10.01.2014
comment
Сначала я долго нажимаю на ячейку, и всплывающее меню срабатывает, независимо от того, устанавливаю ли я распознаватель жестов в табличном представлении или в каждой ячейке табличного представления, отправитель является распознавателем, и я считаю, что это правда, если распознаватель находится на ячейка, как вы предложили, будет ячейкой распознавателя. Но проблема не в этом. Мне нужно получить доступ к ячейке в функции обратного вызова пункта меню, когда я нажимаю всплывающее меню. В этом случае отправителем функции обратного вызова всегда является само меню. - person Hai; 10.01.2014
comment
Что ж, если у вас есть доступ к ячейке и вы установили ivar для selectedCell, а затем получите доступ к ivar selectdCell из этой функции, у вас нет доступа к ячейке, вместо этого она может работать... имейте в виду, что там возможно состояние гонки. Кроме того, как насчет использования indexPathForSelectedRow табличного представления, а затем cellForRowAtIndexPath? - person valheru; 10.01.2014
comment
Привет, valheru, ты имеешь в виду, что я создаю свойство в своем tableviewcontroller и сохраняю ячейку, на которую я долго нажимал, и получаю доступ к свойству ячейки в функции обратного вызова меню :) Да, это обходной путь, однако... извините , я не думаю, что это хороший способ. Спасибо. - person Hai; 11.01.2014
comment
да, вы правы, это не «лучший» обходной путь. Получение выбранного пути лучше - person valheru; 11.01.2014

Спасибо Валеру. Я нахожу «хороший» подход для достижения этого :)

Шаг первый: в MyTableViewController.m

- (void)viewDidLoad
{
    [super viewDidLoad];

    UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
    longPressGesture.minimumPressDuration = .5;
    longPressGesture.delegate = self;
    [self.view addGestureRecognizer:longPressGesture];
}

которые регистрируют распознаватель жестов длительного нажатия на контроллере табличного представления.

- (BOOL)canBecomeFirstResponder
{
    return YES;
}

что позволяет MyTableViewController реагировать на долгое нажатие и всплывающее контекстное меню.

-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
    if(gestureRecognizer.state == UIGestureRecognizerStateBegan)
    {
        CGPoint point = [gestureRecognizer locationInView:self.tableView];
        NSIndexPath * indexPath = [self.tableView indexPathForRowAtPoint:point];
        if(indexPath == nil) return ;

        MyCell *cell = (MyCell *)[self.tableView cellForRowAtIndexPath:indexPath];
        UIMenuItem *determine = [[UIMenuItem alloc] initWithTitle:@"My Action on this cell" action:@selector(handleMyAction:)];
        UIMenuController *menu = [UIMenuController sharedMenuController];
        [menu setMenuItems:[NSArray arrayWithObjects:determine, nil]];
        [menu setTargetRect:cell.frame inView:cell.superview];
        [menu setMenuVisible:YES animated:YES];
        [cell becomeFirstResponder]; //here set the cell as the responder of the menu action
        cell.delegate = self;// this is optional, if you don't want to implement logic in cell class
    }
}

создайте UIMenuController и всплывающее окно, когда я долго нажимаю на ячейку.

-(void)handleMyAction: (UITableViewCell *)cell
{
    NSLog(@"%@", cell);
}

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

Шаг второй: создайте подкласс UITableViewCell с именем MyCell.

В MyCell.h определяет контроллер табличного представления, которому ячейка принадлежит как делегату ячейки. И функция обратного вызова при нажатии на пункт меню

@property (nonatomic, strong) MyTableViewController *delegate;
-(void)handleMyAction:(id)sender;

в MyCell.m

- (BOOL)canBecomeFirstResponder
{
    return YES;
}

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
    if(action == @selector(handleMyAction:))
    {
        return YES;
    }
    return NO;
}

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

-(void)handleMyAction:(id)sender
{
    [self.delegate handleMyAction:self]; //it's a coincidence both functions have the same name:)
}

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

person Hai    schedule 10.01.2014

Сначала объявите тип NSIndexPath как переменную класса.

@property (nonatomic, strong) NSIndexPath *savedIndexPathForThePressedCell;

Теперь в функции распознавания жестов при длительном нажатии получите TableViewCell, используя представление распознавателя. Теперь сохраните IndexPath для TableViewCell.

     - (void)longPressGestureFunction:(UILongPressGestureRecognizer *)recognizer
    {
        UITableViewCell *lTableViewCell = (UITableViewCell *)recognizer.view;
        [lTableViewCell becomeFirstResponder];

        /*Save the Indexpath of the cell pressed*/
        self.savedIndexPathForThePressedCell = [mTableView indexPathForCell:lTableViewCell];

if (recognizer.state == UIGestureRecognizerStateBegan)
    {
        UIMenuItem *MenuDelete = [[UIMenuItem alloc] initWithTitle:@"Delete" action:@selector(Delete:)];
        UIMenuItem *MenuForward = [[UIMenuItem alloc] initWithTitle:@"Forward" action:@selector(Forward:)];
        UIMenuItem *MenuAddToContacts = [[UIMenuItem alloc] initWithTitle:@"Add To Contacts" action:@selector(addToContacts:)];

        mSharedMenu = [UIMenuController sharedMenuController];
[mSharedMenu setMenuItems:[NSArray arrayWithObjects: MenuDelete, MenuForward, nil]];

        [mSharedMenu setMenuVisible:YES animated:YES];
    }

Теперь в методе выбора меню выберите строку на основе сохраненного indexPath.

- (void)Delete:(id)sender {
//  NSLog(@"\n Delete Selected \n");

    [mTableView setEditing:YES animated:YES];

    [mTableView selectRowAtIndexPath:self.savedIndexPathForThePressedCell animated:YES scrollPosition:UITableViewScrollPositionNone];
}

Надеюсь, это поможет!!!

person Pradeep Reddy Kypa    schedule 03.12.2015