iOS: el menu emergente no se comporta de acuerdo con el primer set de respuestas

Tengo varios objects que henetworkingan UIView en mi aplicación que están rastreando los toques en ellos y presentando Copiar / Pegar pop-up si contienen algunos datos específicos. Cuando aparece la window emergente, también cambio la apariencia del object.

Así es como se implementa:

 - (void)viewDidReceiveSingleTap:(NSNotification *)n { MyObject *mo = (MyObject *)n.object; [mo becomeFirstResponder]; UIMenuController *menu = [UIMenuController shanetworkingMenuController]; [menu update]; [menu setTargetRect:CGRectMake(...) inView:mo]; [menu setMenuVisible:YES animated:YES]; } 

MyObject class MyObject , a su vez, define canBecomeFirstResponder: y canResignFirstResponder: siempre devuelve YES . becomeFirstResponder: resignFirstResponder: y canPerformAction:withSender: también se define en consecuencia (aquí es donde cambio la apariencia del object).

Esto es lo que va mal:

viewDidReceiveSingleTap: el object 1. El método viewDidReceiveSingleTap: above recibe una llamada, y el object's canBecomeFirstResponder: y becomeFirstResponder: también reciben llamadas. El menu emergente se muestra como se esperaba.

viewDidReceiveSingleTap: otro object 2. viewDidReceiveSingleTap: se vuelve a llamar y aquí es donde comienza el problema. Primero, canResignFirstResponder: resignFirstResponder: del object 1 se llama, pero no siempre, y no puedo descifrar el patrón. canBecomeFirstResponder: y becomeFirstResponder: del object 2 se llaman correctamente, pero el menu emergente no se reubica. Simplemente desaparece (aunque en viewDidReceiveSingleTap: claramente llamo setMenuVisible:YES ). Para que aparezca, tengo que tocar nuevamente el object 2 (o cualquier otro); en este caso, puedo ver desde el depurador que el object 2 se configuró como un primer respondedor, es solo el pop-up que no estaba apareciendo

¿Qué estoy haciendo mal? ¿Alguna pista sobre la relación entre la visibilidad del menu emergente y el primer respondedor?

El problema es que, cuando tocas en cualquier lugar excepto en el menu, hace un escondite animado de sí mismo. Ese escondite está tomando precedencia sobre tu progtwig animado. Por lo tanto, si toca una vista para mostrar el menu, toque en cualquier otro lugar (ya sea en otra de esas vistas o simplemente en cualquier otro lugar), y luego toque otra de esas vistas, el menu mostrará todas las veces.

Creo que hay un buen argumento para hacer para mantener ese comportamiento, porque es el comportamiento estándar que los usuarios esperan. Pero, por supuesto, tienes una mejor idea de lo que tiene sentido para tu aplicación. Entonces, aquí está el truco:

 [menu setMenuVisible:NO animated:NO]; [menu setMenuVisible:YES animated:YES]; 

Aquí está el código que usé para probarlo:

 @implementation MenuView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.backgroundColor = [UIColor blueColor]; } return self; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [self becomeFirstResponder]; UIMenuController *menu = [UIMenuController shanetworkingMenuController]; UIMenuItem *item = [UIMenuItem alloc] initWithTitle:@"Test" action:@selector(test)]; NSArray *items = [NSArray arrayWithObject:item]; [item release]; [menu setMenuItems:items]; [menu setTargetRect:self.bounds inView:self]; [menu setMenuVisible:NO animated:NO]; [menu setMenuVisible:YES animated:YES]; } - (void)test { NSLog(@"Test!"); } - (BOOL)canPerformAction:(SEL)action withSender:(id)sender { return action == @selector(test); } - (BOOL)canBecomeFirstResponder { NSLog(@"Can become called"); return YES; } - (BOOL)canResignFirstResponder { NSLog(@"Can resign called"); return YES; } - (BOOL)becomeFirstResponder { [super becomeFirstResponder]; NSLog(@"Become called"); return YES; } - (void)dealloc { [super dealloc]; } @end