2009-07-18 5 views
19

que estoy tratando de conseguir el trabajo siguiente código:¿Cómo hacer que UIMenuController funcione para una vista personalizada?

UIMenuController * menu = [UIMenuController sharedMenuController]; 
[menu setTargetRect: CGRectMake(100, 100, 100, 100) inView: self.view]; 
[menu setMenuVisible: YES animated: YES]; 

La instancia menú está listo pero no muestra - la anchura es siempre cero.

¿O hay algún código de muestra en este tema UIPasteboard/UIMenuController?

Respuesta

0

No tiene que agregar el UIMenuController* menu a la subvista principal, E.G. self.view? Creo que es algo así como [self.view addSubView:menu.view]; O me estoy perdiendo el sentido de su pregunta. Es posible que también desee establecer el marco de la vista del menú.

0

UIMenuController no tiene una vista. Me acaba de buscar un código de iPhone Application Programming Guide: Event Handling de manzana:

Listado 3-4 Visualización del menú de edición de

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 
    UITouch *theTouch = [touches anyObject]; 

    if ([theTouch tapCount] == 2 && [self becomeFirstResponder]) { 

     // selection management code goes here... 

     // bring up editing menu. 
     UIMenuController *theMenu = [UIMenuController sharedMenuController]; 
     CGRect selectionRect = CGRectMake(currentSelection.x, currentSelection.y, SIDE, SIDE); 
     [theMenu setTargetRect:selectionRect inView:self]; 
     [theMenu setMenuVisible:YES animated:YES]; 
    } 
} 
+0

el comentario tiene el límite de caracteres, así que publico el código aquí. –

+0

acaba de encontrar una solución alternativa: Ponga un UITextField invisible en la vista y conviértalo en el primer respondedor. Luego, el menú copiar y pegar aparecerá correctamente. –

+0

Estoy teniendo el mismo problema (mi vista personalizada es una subclase de UITableViewCell, pero de lo contrario es la misma situación). Un UITextField invisible no me está ayudando. El menú aún no se muestra y el menúFrame sigue siendo todo ceros. Además, el teclado aparece cada vez que hago de UITextField un firstResponder. ¿Puedes publicar un código de muestra para tu trabajo? –

1
// MyView.h 

@interface MyView : UIView { 
    IBOutlet UITextField * textField_; 
} 

@end 

// MyView.m 

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ 
    NSLog(@"show menu"); 

    [textField_ becomeFirstResponder]; 
    // [self.window becomeFirstResponder]; 

    UIMenuController * menu = [UIMenuController sharedMenuController]; 
    [menu setTargetRect: CGRectMake(0, 0, 100, 10) inView: self]; 
    [menu setMenuVisible: YES animated: YES]; 

    NSLog(@"menu width %f, visible %d", menu.menuFrame.size.width, menu.menuVisible); 
} 

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

Es necesario añadir más código en canPerformAction: withSender: - debe comprobar el cartón y su estado de selección. La guía de programación de aplicaciones para iPhone de Apple proporciona varios fragmentos de código.

7

Si va a implementar una vista personalizada y que la vista se supone que es el que responde (en oposición a algún otro punto de vista, como un UITextField), es necesario reemplazar la función canBecomeFirstResponder en su opinión y volver SÍ:

- (BOOL)canBecomeFirstResponder { 
    return YES; 
} 

entonces, cuando se está mostrando el menú, que debe hacer algo como lo siguiente:

- (void)myMenuFunc { 
    if (![self becomeFirstResponder]) { 
     NSLog(@"couldn't become first responder"); 
     return; 
    } 

    UIMenuController *theMenu = [UIMenuController sharedMenuController]; 
    CGRect selectionRect = CGRectMake(0, 0, 0, 0); 
    [theMenu setTargetRect:selectionRect inView:self]; 
    [theMenu setMenuVisible:YES animated:YES]; 
} 
4

para mostrar UIMenuController hay que añadir siguiente

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender 
{ 
    if (action == @selector(cut:)) 
     return NO; 
    else if (action == @selector(copy:)) 
     return YES; 
    else if (action == @selector(paste:)) 
     return NO; 
    else if (action == @selector(select:) || action == @selector(selectAll:)) 
     return NO; 
    else 
     return [super canPerformAction:action withSender:sender]; 
} 
+0

¿me puede decir cómo agregar la opción Forward en esto? Lo estoy buscando así que ¡ayúdame en eso ...! – Vivek2012

2

creo que Cam tiene razón, es necesario que anula tanto canPerformAction y canBecomeFirstResponder

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

- (BOOL)canBecomeFirstResponder { 
    return YES; 
} 
48

yo no era capaz de conseguir que funcione incluso cuando leí todas sus respuestas. Estoy presentando un código listo que funcionará para todos.

Digamos que tenemos una clase de controlador llamada Controller. Usted puede simplemente pegar el código siguiente para este controlador para tener el menú de trabajo en su opinión:


- (void)loadView { 
    [super loadView]; 

    UILongPressGestureRecognizer *gr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)]; 
    [self.view addGestureRecognizer:gr];  
} 

- (void) longPress:(UILongPressGestureRecognizer *) gestureRecognizer { 
    if ([gestureRecognizer state] == UIGestureRecognizerStateBegan) { 
     CGPoint location = [gestureRecognizer locationInView:[gestureRecognizer view]]; 
     UIMenuController *menuController = [UIMenuController sharedMenuController]; 
     UIMenuItem *resetMenuItem = [[UIMenuItem alloc] initWithTitle:@"Item" action:@selector(menuItemClicked:)]; 

     NSAssert([self becomeFirstResponder], @"Sorry, UIMenuController will not work with %@ since it cannot become first responder", self); 
     [menuController setMenuItems:[NSArray arrayWithObject:resetMenuItem]]; 
     [menuController setTargetRect:CGRectMake(location.x, location.y, 0.0f, 0.0f) inView:[gestureRecognizer view]]; 
     [menuController setMenuVisible:YES animated:YES]; 
    } 
} 

- (void) copy:(id) sender { 
    // called when copy clicked in menu 
} 

- (void) menuItemClicked:(id) sender { 
    // called when Item clicked in menu 
} 

- (BOOL) canPerformAction:(SEL)selector withSender:(id) sender { 
    if (selector == @selector(menuItemClicked:) || selector == @selector(copy:)) { 
     return YES; 
    } 
    return NO; 
} 

- (BOOL) canBecomeFirstResponder { 
    return YES; 
} 

Lo que hay que hacer para que el menú de trabajo es que el firstResponder (en nuestro caso nuestro controlador - ver la línea con [libre becomeFirstResponder]) tiene que ser capaz de convertirse en primer respondedor (override método canBecomeFirstResponder aplicación causa predeterminada devuelve NO), así como - (BOOL) canPerformAction:(SEL)selector withSender:(id) sender que debe devolver SÍ a cualquier acción que puede ser realizado por firstResponder

+5

Es posible que desee cambiar esa afirmación para usar canBecomeFirstResponder, y poner el becomeFirstResponder fuera del assert;) – antsyawn

+0

Esto funciona perfectamente. Al principio me preocupó un poco que [self becomeFirstResponder] subiera el teclado, pero no fue así. ¡Gracias! –

+0

En el método de copia, ¿cómo puedo obtener el texto seleccionado? para copiar a UIPasteboard –

6

En caso de que alguien todavía tiene problemas: Mi menú solía funcionar y algún día dejó de funcionar milagrosamente. Todo lo demás en mi aplicación todavía funcionaba. Ahora había eliminado el método [window makeKeyAndVisible] del método application:didFinishLaunchingWithOptions:, y mientras todo lo demás funcionaba, ¡esto rompe UIMenuController!

error estúpido de mi parte, difícil de encontrar al culpable ...

+1

Gracias por esto. Resulta que me pasó, no estoy seguro de cómo se eliminó la línea makeKeyAndVisible, pero sin ella casi destruí mi monitor y usé sus bordes afilados para cometer Hari-Kari. –

+1

Muchas gracias. Estaba presentando una lupa en su propia ventana y necesitaba volver a hacer que la tecla de la ventana principal funcionara para UIMenuController. – hatfinch

0

lo hice de la siguiente manera a continuación. Simplemente llame al método que muestra el menú después de un retraso muy corto en init. No quise llamarlo desde View Controller y tampoco encontré un evento que indique que apareció mi vista personalizada y estoy listo para mostrar el menú. Así que esta manera está bien desde mi perspectiva. El retraso puede ser menor, pero depende de usted.

@implementation DTSignatureImageView 

- (id)initWithImage:(UIImage *)image 
{ 
    self = [super initWithImage:image]; 
    if(self){ 
     self.contentMode = UIViewContentModeScaleAspectFit; 
     self.frame = CGRectMake(0, 0, image.size.width/2.5, image.size.height/2.5); 
     self.userInteractionEnabled = YES; 

     UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(signatureDidPan:)]; 
     [self addGestureRecognizer:pan]; 

     [self becomeFirstResponder]; 

     [self performSelector:@selector(showMenu) withObject:nil afterDelay:0.5]; 
    } 

    return self; 
} 

- (BOOL)canBecomeFirstResponder 
{ 
    return YES; 
} 

- (void)showMenu 
{ 
    UIMenuController *menu = [UIMenuController sharedMenuController]; 
    menu.menuItems = @[ 
     [[UIMenuItem alloc] initWithTitle:@"Apply" action:@selector(applySignature)], 
     [[UIMenuItem alloc] initWithTitle:@"Update" action:@selector(updateSignature)], 
     [[UIMenuItem alloc] initWithTitle:@"Clear" action:@selector(delegateSignature)]]; 
    [menu setTargetRect:self.bounds inView:self]; 
    [menu setMenuVisible:YES animated:YES]; 
} 

- (NSArray *)menuActions 
{ 
    static NSArray *actions = nil; 
    if (actions == nil){ 
     actions = @[ 
        NSStringFromSelector(@selector(applySignature)), 
        NSStringFromSelector(@selector(updateSignature)), 
        NSStringFromSelector(@selector(delegateSignature))]; 
    } 

    return actions; 
} 

- (void) signatureDidPan: (UIPanGestureRecognizer *)gesture 
{ 
    switch (gesture.state) { 
     case UIGestureRecognizerStateBegan: { 
      [[UIMenuController sharedMenuController] setMenuVisible:NO animated:YES]; 
      break; 
     } 

     case UIGestureRecognizerStateEnded: { 
      [self becomeFirstResponder]; 
      [self showMenu]; 
     } 

     default: 
      break; 
    } 

    CGPoint point = [gesture locationInView:gesture.view.superview]; 
    gesture.view.center = point; 
} 
Cuestiones relacionadas