2010-06-24 17 views
55

Estoy intentando crear un UIMenuController personalizado y mostrarlo en mi vista. Aquí está mi código:UIMenuController no aparece

UIMenuController *menuController = [UIMenuController sharedMenuController]; 
    UIMenuItem *listMenuItem = [[UIMenuItem alloc] initWithTitle:@"List" action:@selector(addList:)]; 

    [menuController setMenuItems:[NSArray arrayWithObject:listMenuItem]]; 
    [menuController setTargetRect:CGRectMake(50.0, 50.0, 0, 0) inView:self.view]; 
    [menuController setMenuVisible:YES animated:YES]; 

    [listMenuItem release]; 

No hay errores o excepciones, pero el controlador de menú simplemente no aparece.

Respuesta

142

que tiene que hacer tres cosas:

  1. es necesario llamar a -becomeFirstResponder la vista o el controlador de vista.
  2. Su controlador de vista o vista necesita implementar -canBecomeFirstResponder (devolviendo YES).
  3. Opcionalmente, su controlador de vista o vista puede implementar -canPerformAction:action withSender:sender para mostrar/ocultar elementos de menú de manera individual.
+2

Útil, muy útil. – Jake

+0

Esto también funciona muy bien en MonoTouch; solo hay que tener en cuenta que el 'CanBecomeFirstResponder' es una propiedad que se reemplaza, y que debe asignar una matriz' UIMenuItem [] 'a la propiedad' UIMenuController.MenuItems'. – PaulJ

+4

No funcionó cuando llamé a 'becomeFirstResponder' * en la vista *. Llamarlo al controlador funcionó bien. –

-1

quizás porque CGRectMake(50.0, 50.0, 0, 0) crea un CGRect con width = 0 y height = 0?

aplausos, anka

+0

Incluso si configuro el ancho/alto a algo así como 100, aún no aparece. – indragie

+0

Bien, puede intentar agregar el método (BOOL) canPerformAction: (SEL) acción con el remitente: (id) y devolver SÍ. – anka

+0

Todavía no funciona. – indragie

15

UIMenuController es visible en cualquier caso sólo si la vista es el primero en responder y

- (BOOL)canPerformAction método devuelve YES

Por tanto, si el controlador de menú es para ser mostrado en el botón de clic, la primera línea en el la acción del botón debe ser [self becomeFirstResponder]. NOTA: aquí está la vista que presentará los menús.

Si sus menús se van a mostrar en tiempo gesto de prensa, a continuación, añadir longPressGesture a la UIView y en el caso LongPress antes de escribir

[menuController setTargetRect:CGRectMake(50.0, 50.0, 0, 0) inView:self.view]; 
[menuController setMenuVisible:YES animated:YES]; 

escritura [self becomeFirstResponder];

A continuación, siga los pasos mencionados por OZ.

+0

Intenté esto pero no funciona para mí. Como el comentario tiene límite, he creado otra pregunta http://stackoverflow.com/questions/16054050/uimenucontroller-not-getting-displayed – JiteshW

+0

Gracias, el targetRect hizo el truco para mí. Extraño porque tengo otra clase casi idéntica que funciona bien sin ella. – Kalle

2

En caso de que alguien tenga este problema específicamente (y aleatoriamente) con iOS6: puede consultar this SO relacionado con tener habilitada la selección de voz en el dispositivo (Configuración -> General -> Accesibilidad -> Hablar selección: activada) Un pequeño número de mis usuarios no pudieron ver el UIMenuItems personalizado y esta fue la causa.

4

El siguiente es un ejemplo de trabajo comentado completo ...

Ver archivo de cabecera subclase

#import <Foundation/Foundation.h> 

@interface MenuControllerSupportingView : UIView 
{ 

} 
@end 

Ver archivo de origen subclase

#import "MenuControllerSupportingView.h" 

@implementation MenuControllerSupportingView 

//It's mandatory and it has to return YES then only u can show menu items.. 
-(BOOL)canBecomeFirstResponder 
{ 
    return YES; 
} 

-(void)MenuItemAClicked 
{ 
    NSLog(@"Menu item A clicked"); 
} 

-(void)MenuItemBClicked 
{ 
NSLog(@"Menu item B clicked"); 
} 

-(void)MenuItemCClicked 
{ 
    NSLog(@"Menu item C clicked"); 
} 

//It's not mandatory for custom menu items 

-(BOOL)canPerformAction:(SEL)action withSender:(id)sender 
{ 
    if(action == @selector(MenuItemAClicked)) 
    return YES; 
    else if(action == @selector(MenuItemBClicked)) 
    return YES; 
    else if(action == @selector(MenuItemCClicked)) 
    return YES; 
    else 
    return NO; 
} 

archivo de cabecera Vista Controlador

#import <UIKit/UIKit.h> 

@interface ViewController1 : UIViewController 

@end 

archivo de vista de origen Controlador

#import "ViewController1.h" 
#import "MenuControllerSupportingView.h" 

@interface ViewController1() 
{ 
MenuControllerSupportingView *vu; 
} 
@end 

@implementation ViewController1 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    vu=[[SGGI_MenuControllerSupportingView alloc]initWithFrame:CGRectMake(0,0,768,1024)]; 

[self.view addSubview:vu]; 

UIButton *btn=[UIButton buttonWithType:UIButtonTypeCustom]; 

[btn setFrame:CGRectMake(200,200,200,30)]; 

[btn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; 

[btn setTitle:@"Show" forState:UIControlStateNormal]; 

[btn addTarget:self action:@selector(SHowMenu) forControlEvents:UIControlEventTouchUpInside]; 

[vu addSubview:btn]; 

} 

-(void)SHowMenu 
{ 
UIMenuController *menucontroller=[UIMenuController sharedMenuController]; 

UIMenuItem *MenuitemA=[[UIMenuItem alloc] initWithTitle:@"A" action:@selector(MenuItemAClicked)]; 

UIMenuItem *MenuitemB=[[UIMenuItem alloc] initWithTitle:@"B" action:@selector(MenuItemBClicked)]; 

UIMenuItem *MenuitemC=[[UIMenuItem alloc] initWithTitle:@"C" action:@selector(MenuItemCClicked)]; 

[menucontroller setMenuItems:[NSArray arrayWithObjects:MenuitemA,MenuitemB,MenuitemC,nil]]; 

    //It's mandatory 
[vu becomeFirstResponder]; 

    //It's also mandatory ...remeber we've added a mehod on view class 
if([vu canBecomeFirstResponder]) 
{ 

    [menucontroller setTargetRect:CGRectMake(10,10, 0, 200) inView:vu]; 

    [menucontroller setMenuVisible:YES animated:YES]; 
} 

} 




-(void)didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 

} 

@end 

En vista de clase, si u escribir volver SÍ solo en canPerformAction verá todos los menuitems por defecto, como símbolo de la cámara, cortar, copiar, etc ..

-(BOOL)canPerformAction:(SEL)action withSender:(id)sender 
{ 
return YES; 
} 

si quieres mostrar algo como cámara por sí sola entonces

-(BOOL)canPerformAction:(SEL)action withSender:(id)sender 
{ 
if([email protected](_insertImage:)) 
    return YES; 
else 
    return NO; 

} 

si quieres saber acerca de todas las acciones luego

visita del link

13

La respuesta menciona tres cosas, pero para ser exigente, hay seis:

manejador
  1. El menú debe ser un UIView. Si no lo es, -becomeFirstResponder falla.
  2. El controlador de menú debe tener userInteractionEnabled = YES
  3. El controlador de menú debe estar en la jerarquía de vistas y su propiedad -window debe ser la misma que la ventana de la vista en el argumento inView:.
  4. Debe implementar -canBecomeFirstResponder y devolver YES.
  5. Debe llamar al [handler becomeFirstResponder], antes de llamar al[menu setTargetRect:inView:], o este último fallará.
  6. Debe llamar al [menu setTargetRect:inView] (al menos una vez) y [menu setMenuVisible:animated:].

En particular, los puntos 1-3 anteriores me consiguieron. Quería una clase de controlador de menú personalizado que fuera UIResponder al principio, lo que ocasionó que -becomeFirstResponder devolviera NO; entonces fue un UIView, que falló, luego intenté hacerlo un UIButton que funcionó, pero solo porque userInteractionEnabled tiene por defecto YES para botones y NO para UIView s.

+1

Esta debería ser la respuesta aceptada. – Grimxn

0

En Swift 3.0 -

En mi caso, yo quería tener el VC pre-seleccionar el texto en un TextView y mostrar un menú personalizado para el usuario para tomar una decisión sobre esa selección. Como se menciona en Kalle, el orden es muy importante, especialmente al hacer setMenuVisible al final.

En VC, viewDidLoad:

menuCont = UIMenuController.shared 
let menuItem1: UIMenuItem = UIMenuItem(title: "Text", action: #selector(rtfView.textItem(_:))) 
let menuItems: NSArray = [menuItem1] 
menuCont.menuItems = menuItems as? [UIMenuItem] 

En VC, cuando el usuario pulsa un botón:

@IBAction func pressed(_ sender: Any) { 
    self.textView.selectedRange = NSMakeRange(rangeStart, rangeLength) 
    self.textView.becomeFirstResponder() 
    menuCont.setTargetRect(CGRect.zero, in: self.textView) 
    menuCont.setMenuVisible(true, animated: true) 
} 

Por último, en la sub-clase de la Vista de Texto:

class rtfView: UITextView { 

override var canBecomeFirstResponder: Bool { 
    return true 
} 

override func canPerformAction(_ action: Selector, withSender sender: Any!) -> Bool { 
    if (action == #selector(textItem(_:))) { 
     return true 
    } else { 
     return false 
    } 
    } 
}