ObjecTips

Swift & Objective-C で iOS とか macOS とか

UITableViewCell 選択時にメニューを表示する

前回は UITableViewDelegate を使って簡単にメニュー表示をする方法について書いた。

この方法はセルを長押しした時にメニューを表示する事ができるが、セルをタップして選択したらすぐにメニューを表示したい場合がある。

この場合は前回紹介した
- tableView:shouldShowMenuForRowAtIndexPath:
- tableView:canPerformAction:forRowAtIndexPath:withSender:
- tableView:performAction:forRowAtIndexPath:withSender:

これらの UITableViewDelegateメソッドを使わないで、セルの選択時に直接コードで UIMenuController を表示するよう実装する。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UIMenuController *menuController = [UIMenuController sharedMenuController];
    CGRect rect = [tableView rectForRowAtIndexPath:indexPath];
    [menuController setTargetRect:rect inView:tableView];
    [menuController setMenuVisible:YES animated:YES];
}

それぞれ実行したいメソッド copy: paste: cut: も実装する。
実装内容は前回と全く同じコード

- (void)copy:(id)sender
{
    NSIndexPath *indexPath = self.tableView.indexPathForSelectedRow;
    // copy content to pasteboard
    NSString *string = self.list[indexPath.row];
    [UIPasteboard generalPasteboard].string = string;
}

- (void)paste:(id)sender
{
    NSIndexPath *indexPath = self.tableView.indexPathForSelectedRow;
    // retrieve content from pasteboard
    NSString *string = [UIPasteboard generalPasteboard].string;
    // replace content in list
    self.list[indexPath.row] = string;
    // configure tableview
    [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}

- (void)cut:(id)sender
{
    NSIndexPath *indexPath = self.tableView.indexPathForSelectedRow;
    // copy content to pasteboard
    NSString *string = self.list[indexPath.row];
    [UIPasteboard generalPasteboard].string = string;
    // delete content from list
    [self.list removeObjectAtIndex:indexPath.row];
    // configure tableview
    [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}

そして重要、というか忘れやすいのが

- (BOOL)canBecomeFirstResponder
{
    return YES;
}

これを実装して ViewController が firstResponder になれるようにする事。
これをしないとメニューが表示されない。

あと最後に、
これらの実装だけだとメニュー表示がキャンセルされた時にセルの選択状態が解除されないという現象が起きるので、メニューが非表示になる際にセルを deselect する。
メニューが非表示になるタイミングは UIMenuControllerWillHideMenuNotification を使って通知を受け取る事ができる。

全体の実装は以下

いい感じに実装できた。


関連