Quiero que el UIMenuController que aparece cuando yo pulse durante un UITableViewCell para mostrar personalizado UIMenuItems.

Puedo configurar el elemento personalizado en viewDidLoad

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

Y entonces me puse de todos los métodos de delegado.

- (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;
}

Pero todo lo que hace, es mostrar la «Copia» elemento, ya que sólo lo permite y mi elemento personalizado. El elemento personalizado, sin embargo, no se mostrará.

Me doy cuenta, yo podría agregar un gesto de reconocimiento a la célula en sí, pero ese tipo de derrotas el propósito de la instancia compartida de UIMenuController, ¿no?

3 Comentarios

  1. 51

    Que tengo entendido que hay dos problemas principales:

    1) que usted espera tableView canPerformAction: a la ayuda personalizada de los selectores, mientras que la documentación dice que sólo admite dos de UIResponderStandardEditActions (copia y/o pasta);

    2) no hay necesidad de que la parte || action == @selector(test:) como agregar el menú personalizado las opciones de inicialización menuItems de la propiedad. Para este tipo de elementos de los selectores de la comprobación será automático.

    Lo que usted puede hacer para obtener el elemento de menú personalizado muestra y el trabajo es:

    1) Revisión de la tabla de la vista de los métodos de delegado con

    a)

    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) la Instalación de las celdas (subclases UITableViewCell) con

    -(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 {
    
    }
    ///////////////////////////////////////////////////////
    • Oh, la segunda parte fue la solución. Gracias por roce mi nariz con la documentación pertinente, así!
    • Gracias, me ayudó demasiado, pero he realizado un cambio: he implementado mi método personalizado (test: en tu ejemplo) y el respondedor método de consulta (canPerformAction:withSender:) en mi punto de vista controlador en lugar de en una vista de tabla de la subclase. UIResponder se ocupa de ir por el respondedor de la cadena, por lo que una subclase no debería ser necesario si es sólo para este problema. Este repuestos mí un dolor de cabeza — como el método personalizado tiene un lindo nombre distinto para evitar colisiones. 😉
    • Gracias por el comentario, @Randy Marsh, sólo espero que su controlador de vista no va a conseguir tan grande como miles de líneas 🙂
    • Yo prefiero a colocar las cosas en un archivo y usar #pragma mark a la estructura de las cosas que tienen muchas clases y archivos. Pero sí, yo fácilmente llega a miles de líneas. ;-p
    • Me estoy poniendo problemas para obtener llamado canPerformAction al entrar en este UITableView Controlador de UITabBar menú acción.
    • Ostwal, asegúrese de que está utilizando la subclase de la aplicación de los métodos, y no otra subclase o estándar UITableViewCell. Si usted no desea subclase UITableViewCell, los métodos pueden ser implementados en «super» respondedor, por ejemplo, el controlador de vista.
    • Gracias. Puede usted por favor, busque en mi pregunta una vez en stackoverflow.com/questions/21852971/…
    • Me fijo su retorno de tipo BOOL en el performAction formato tableview método, que debería haber sido un vacío.
    • Tienes razón, no sé por qué su edición fue rechazada, vamos a arreglarlo.
    • Esta solución no funciona en ios 7. Alguna idea sobre esto?
    • Ostwal he comprobado y estoy convencida de que la solución está trabajando muy bien en iOs 7.1. Realmente no puedo ver ninguna razón por la que dejaría de funcionar, usted necesita para comprobar su aplicación.
    • He comprobado mi aplicación. Es como lo mismo como respuesta que dio. Estoy probando en el iPad con ios 7.0.4. Copia el elemento de menú mostrar, pero el elemento de menú personalizado no viene.
    • En lugar de estándar de todos los elementos de menú que se muestra, pero el elemento de menú personalizado no viene. Es posible que no agregan sharedMenuController del menuItems?
    • Ostwa, asegúrese de que los métodos de 2) se ponen en práctica en su celda personalizada, en formato tableview o cualquier otra clase de interfaz de usuario que está utilizando, que está involucrada en las acciones de la cadena.
    • Me gustaría que te invitamos a contestar esta pregunta, stackoverflow.com/questions/31183894/…

  2. 8

    Para implementar copia y una acción personalizada para UITableViewCell:

    Una vez en su aplicación, registro de la acción personalizada:

    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()
    }

    En su UITableViewCell subclase, implementar el método personalizado:

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

    En su UITableViewDelegate, implementar los siguientes métodos:

    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()
        }
    }

    Notas:

    • gracias esto realmente me ayudó. esto funciona cuando se pulsa de forma prolongada en el celular, sin embargo, podemos realizar el mismo cuando yo simplemente haga clic en la celda ? y también ¿cómo puedo quitar la opción «Copiar», su todavía allí, junto con mi costumbre de veces. gracias 🙂
    • Tenga en cuenta que el uso de Xcode8/swift3 y el suministro de return action == "copy:" a canPerformAction desencadena una solución que genera return action == #selector(UIResponderStandardEditActions.copy(_:))
  3. 1

    SWIFT 3:

    En el AppDelegate didFinishLaunchingWithOptions:

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

    en su TableViewContoller Clase:

    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
       }
    }
    • Usted sólo debe realizar las UIMenuController programa de instalación una vez durante la vida de su aplicación. De lo contrario, obtendrá otros elementos de menú cada vez que el se carga la vista.
    • por eso es en viewDidLoad?
    • Si usted fuera a navegar lejos de la UIViewController la vista será liberada para ahorrar memoria. viewDidLoad serán llamados de nuevo la próxima vez que se carga la vista. Usted debería estar bien si el UIViewController es la raíz de la vista, pero si alguna vez mover el UIViewController usted va a duplicar los elementos de menú para su posterior resiste a la UIViewController. viewDidLoad puede ser llamado varias veces dentro de su aplicación a la vida mientras que su AppDelegate del applicationDidFinishLaunching: será llamado una vez, así que creo que este es el mejor lugar para la instalación en el menú.

Dejar respuesta

Please enter your comment!
Please enter your name here