iphone ios objective-c ipad uimenucontroller

iphone - ¿Cómo podría reemplazar UIMenuController con mi propia vista cuando se selecciona el texto?



ios objective-c (2)

Cuando se selecciona el texto, por defecto aparece un UIMenuController con cortar / copiar / pegar, etc.

Me gustaría reemplazarlo con mi propia vista personalizada (de aspecto similar, pero el doble de alta para que pueda tener dos filas de botones / vistas personalizadas). ¿Cómo puedo hacer esto?

Sé que no hay una manera fácil. Espero que si hay una solución fácil, no será muy elegante. El código tampoco puede usar ninguna API privada.

Realmente, realmente preferiría no tener que implementar mi propia vista de texto, reimplementar la selección y entrada de texto, y reimplementar la vista de aumento para poder escribir mi propio clon de UIMenuController si hay alguna forma de evitarlo. Es bastante importante para la interfaz de la aplicación que pueda reemplazar el controlador UIMenu, por lo que si no hay otra respuesta, puedo terminar haciendo esto. Estaré MUY agradecido si alguien me puede ahorrar una buena cantidad de tiempo y proponer otra forma más fácil de hacerlo.


Creo que esto puede ayudarte https://github.com/cxa/UIMenuItem-CXAImageSupport

UIMenuItem usa UILabel para mostrar su título, lo que significa que podemos swizzle -drawTextInRect: para admitir la imagen.

UIMenuItem + CXAImageSupport es un truco sucio, pero debería ser seguro en la mayoría de los casos. No contiene ninguna API privada.

Hacer una categoría en lugar de crear subclases para UIMenuItem gana más flexibilidad. Sí, esta categoría se puede aplicar al increíble PSMenuItem también.


Hay tres cosas importantes que debes saber antes de comenzar:

1) Tendrá que escribir la vista del controlador de menú personalizado, pero supongo que esperaba eso. Solo conozco una implementación commercial de un controlador de menú personalizado, pero esto no debería ser demasiado difícil.

2) Hay un método útil en UIResponder llamado -canPerformAction:withSender: Lea más sobre esto en la referencia de clase UIResponder . Puede usar ese método para determinar si su vista de texto admite una acción estándar específica (definida en el protocolo UIResponderStandardEditActions ).
Esto será útil cuando decida qué elementos mostrar en su controlador de menú personalizado. Por ejemplo, el elemento de menú Pegar solo se mostrará cuando el tablero de trabajo del usuario contenga una cadena para pegar.

3) Puede detectar cuándo se mostrará UIMenuController escuchando la notificación de notificación de UIMenuControllerWillShowMenuNotification .

Ahora que sabes todo eso, así es como empezaría a abordar eso:

1) Escuche UIMenuControllerWillShowMenuNotification s cuando la vista de texto sea el primer respondedor

- (void)textViewDidBeginEditing:(UITextView *)textView { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(menuWillBeShown:) name:UIMenuControllerWillShowMenuNotification object:nil]; } - (void)textViewDidEndEditing:(UITextView *)textView { [[NSNotificationCenter defaultCenter] removeObserver:self name:UIMenuControllerWillShowMenuNotification object:nil]; }

2) Muestre su controlador de menú personalizado en lugar del controlador UIMenuController predeterminado

- (void)menuWillBeShown:(NSNotification *)notification { CGRect menuFrame = [[UIMenuController sharedMenuController] menuFrame]; [[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO]; // Don''t show the default menu controller CustomMenuController *controller = ...; controller.menuItems = ...; // additional stuff goes here [controller setTargetRectWithMenuFrame:menuFrame]; // menuFrame is in screen coordinates, so you might have to convert it to your menu''s presenting view/window/whatever [controller setMenuVisible:YES animated:YES]; }

Misceláneo 1) Puede usar una UIWindow pantalla completa para mostrar su menú personalizado para que pueda superponerse a la barra de estado.

UIWindow *presentingWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; presentingWindow.windowLevel = UIWindowLevelStatusBar + 1; presentingWindow.backgroundColor = [UIColor clearColor]; [presentingWindow addSubview:controller]; [presentingWindow makeKeyAndVisible];

Misceláneo 2) Para determinar qué elementos del menú mostrar, puede usar la mencionada -canPerformAction:withSender:

BOOL canPaste = [textView canPerformAction:@selector(paste:) withSender:nil]; BOOL canSelectAll = [textView canPerformAction:@selector(selectAll:) withSender:nil];

Misceláneo 3) Tendrá que manejar el UITapGestureRecognizer del menú utilizando un UITapGestureRecognizer en la ventana de presentación o algo así.

Esto no será fácil, pero es factible y espero que funcione bien para usted. ¡Buena suerte!

Actualizar:
Una nueva implementación de menú apareció en cocoacontrols.com hoy que quizás desee revisar: https://github.com/questbeat/QBPopupMenu

Actualización 2:
Como se explica en esta respuesta , puede obtener el marco del texto seleccionado de una vista de texto usando -caretRectForPosition: