25

我希望长按 UITableViewCell 以显示自定义 UIMenuItems 时弹出的 UIMenuController。

我在 viewDidLoad 中设置了自定义项

UIMenuItem *testMenuItem = [[UIMenuItem alloc] initWithTitle:@"Test" action:@selector(test:)];
[[UIMenuController sharedMenuController] setMenuItems: @[testMenuItem]];

然后我设置了所有正确的委托方法。

- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}

-(BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
    return (action == @selector(copy:) || action == @selector(test:));
}

- (BOOL)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
    if (action == @selector(copy:)) {
         // do stuff
    }

    return YES;
}

但它所做的只是显示“复制”项目,因为我只允许它和我的自定义项目。但是,自定义项目不会显示。

我意识到,我可以向单元格本身添加一个手势识别器,但这违背了 UIMenuController 共享实例的目的,不是吗?

4

4 回答 4

52

据我了解有两个主要问题:

1)您希望tableView canPerformAction:支持自定义选择器,而文档说它只支持UIResponderStandardEditActions(复制和/或粘贴)中的两个;

2)不需要该部分|| action == @selector(test:),因为您通过初始化menuItems属性添加自定义菜单选项。对于此项目选择器,检查将是自动的。

您可以做些什么来显示和工作的自定义菜单项是:

1)修复表视图委托方法

一种)

UIMenuItem *testMenuItem = [[UIMenuItem alloc] initWithTitle:@"Test" action:@selector(test:)];
[[UIMenuController sharedMenuController] setMenuItems: @[testMenuItem]];
[[UIMenuController sharedMenuController] update];

b)

- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}

-(BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
    return (action == @selector(copy:));
}

- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
    // required
}

2)设置单元格(子类UITableViewCell

-(BOOL) canPerformAction:(SEL)action withSender:(id)sender {
    return (action == @selector(copy:) || action == @selector(test:));
}

-(BOOL)canBecomeFirstResponder {
    return YES;
}

/// this methods will be called for the cell menu items
-(void) test: (id) sender {

}

-(void) copy:(id)sender {

}
///////////////////////////////////////////////////////
于 2012-09-05T23:44:58.517 回答
8

为 UITableViewCell 实现复制和自定义操作:

进入您的应用程序后,注册自定义操作:

struct Token { static var token: dispatch_once_t = 0 }
dispatch_once(&Token.token) {
    let customMenuItem = UIMenuItem(title: "Custom", action: #selector(MyCell.customMenuItemTapped(_:))
    UIMenuController.sharedMenuController().menuItems = [customMenuItem]
    UIMenuController.sharedMenuController().update()
}

在您的UITableViewCell子类中,实现自定义方法:

func customMenuItemTapped(sender: UIMenuController) {
    // implement custom action here
}

在您的UITableViewDelegate中,实现以下方法:

override func tableView(tableView: UITableView, shouldShowMenuForRowAtIndexPath indexPath: NSIndexPath) -> Bool {
    return true
}

override func tableView(tableView: UITableView, canPerformAction action: Selector, forRowAtIndexPath indexPath: NSIndexPath, withSender sender: AnyObject?) -> Bool {
    return action == #selector(NSObject.copy(_:)) || action == #selector(MyCell.customMenuItemTapped(_:))
}

override func tableView(tableView: UITableView, performAction action: Selector, forRowAtIndexPath indexPath: NSIndexPath, withSender sender: AnyObject?) {
    switch action {
    case #selector(NSObject.copy(_:)):
        // implement copy here
    default:
        assertionFailure()
    }
}

笔记:

于 2015-07-11T14:59:49.793 回答
2

仅允许复制第 0 部分的第 0 行的示例

更新到 Swift 5.2

func shouldAllowCopyOn(indexPath: IndexPath) -> Bool {
    if indexPath.section == 0 && indexPath.row == 0 {
       return true
    }
    return false
}

func tableView(_ tableView: UITableView, shouldShowMenuForRowAt indexPath: IndexPath) -> Bool {
    return self.shouldAllowCopyOn(indexPath: indexPath)
}

func tableView(_ tableView: UITableView, canPerformAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
    if (action == #selector(UIResponderStandardEditActions.copy(_:))) {
          return self.shouldAllowCopyOn(indexPath: indexPath)
    }
}

func tableView(_ tableView: UITableView, performAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) {
    if (action == #selector(UIResponderStandardEditActions.copy(_:)) && self.shouldAllowCopyOn(indexPath: indexPath)) {
       if let cell = self.tableView.cellForRow(at: indexPath) as? UITableViewCell {
         self.copyAction(cell: cell)
        }
    }
}

@objc
private func copyAction(cell: UITableViewCell) {
    UIPasteboard.general.string = cell.titleLabel.text
}
于 2021-01-25T16:51:07.633 回答
1

斯威夫特 3:

在 AppDelegate didFinishLaunchingWithOptions 中:

let customMenuItem = UIMenuItem(title: "Delete", action:
#selector(TableViewCell.deleteMessageActionTapped(sender:)))
        UIMenuController.shared.menuItems = [customMenuItem]
        UIMenuController.shared.update()

在您的 TableViewContoller 类中:

override func tableView(_ tableView: UITableView, shouldShowMenuForRowAt indexPath: IndexPath) -> Bool {
    return true
}

override func tableView(_ tableView: UITableView, canPerformAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
        return action == #selector(copy(_:)) || action == #selector(TableViewCell.yourActionTapped(sender:))
    }



 override func tableView(_ tableView: UITableView, performAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) {
   if action == #selector(copy(_:)) {
        let pasteboard = UIPasteboard.general
        pasteboard.string = messages[indexPath.row].text
   }
}
于 2017-02-28T09:32:40.813 回答