web-dev-qa-db-fra.com

UIMenuController ne se présente pas

J'essaie de créer un UIMenuController personnalisé et de l'afficher dans ma vue. Voici mon code:

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];

Il n'y a pas d'erreur ni d'exception, mais le contrôleur de menu ne s'affiche tout simplement pas.

56
indragie

Vous devez faire trois choses:

  1. Vous devez appeler -becomeFirstResponder sur la vue ou le contrôleur de vue.
  2. Votre vue ou votre contrôleur de vue doit implémenter -canBecomeFirstResponder (en retournant YES).
  3. En option, votre contrôleur de vue ou de vue peut implémenter -canPerformAction:action withSender:sender pour afficher/masquer les éléments de menu individuellement.
152
OZ Apps

La réponse mentionne trois choses, mais pour être difficile, il y en a six:

  1. Le gestionnaire de menus doit être un UIView. Si ce n'est pas le cas, -becomeFirstResponder échoue.
  2. Le gestionnaire de menu doit avoir userInteractionEnabled = YES
  3. Le gestionnaire de menus doit figurer dans la hiérarchie des vues et sa propriété -window doit être identique à la fenêtre de la vue dans l'argument inView:.
  4. Vous devez implémenter -canBecomeFirstResponder et renvoyer YES.
  5. Vous devez appeler [handler becomeFirstResponder], avant que le[menu setTargetRect:inView:] soit appelé, sinon ce dernier échouera.
  6. Vous devez appeler [menu setTargetRect:inView] (au moins une fois) et [menu setMenuVisible:animated:].

Les points 1 à 3 ci-dessus m'ont particulièrement attiré. Je voulais une classe de gestionnaire de menus personnalisée qui était une UIResponder au début, ce qui faisait que -becomeFirstResponder retournait NO; alors c'était un UIView, qui a échoué, puis j'ai essayé d'en faire un UIButton qui fonctionnait, mais uniquement parce que userInteractionEnabled est défini par défaut sur YES pour les boutons et NO pour UIViews.

17
Kalle

UIMenuController est visible sur n’importe quelle vue que si la vue est répondeur initial et 

La méthode - (BOOL)canPerformAction renvoie YES

Par conséquent, si votre contrôleur de menu doit être affiché en cliquant sur un bouton, la première ligne de l'action du bouton doit être [self becomeFirstResponder]. NOTE: voici la vue qui présentera les menus.

Si vos menus doivent être affichés par un appui long, ajoutez longPressGesture à UIView et à l'événement longpress avant d'écrire. 

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

écrire [self becomeFirstResponder];

Suivez ensuite les étapes mentionnées par OZ.

15
Snehal

Voici un exemple de travail complet commenté ...

Voir le fichier d'en-tête de sous-classe

#import <Foundation/Foundation.h>

@interface MenuControllerSupportingView : UIView
{

}
@end

Voir le fichier source de la sous-classe

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

voir le fichier d'en-tête du contrôleur

#import <UIKit/UIKit.h>

@interface ViewController1 : UIViewController

@end

voir le fichier source du contrôleur

 #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

Dans la classe View, si u write renvoie YES seul dans canPerformAction, vous verrez tous les menus par défaut tels que le symbole de la caméra, couper, copier, etc.

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

si tu veux montrer quelque chose comme caméra seul alors 

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

}

si tu veux savoir sur toutes les actions alors 

visitez le lien

4
Durai Amuthan.H

Juste au cas où quelqu'un aurait ce problème spécifiquement (et de manière aléatoire) avec iOS6: vous souhaiterez peut-être consulter this SO lié à l'activation de l'option Speak Selection sur le périphérique (Paramètres -> Général -> Accessibilité - > Speak Selection: On). Un petit nombre de mes utilisateurs ne pouvaient pas voir la UIMenuItems personnalisée et c'était la cause.

2
Matthew Leffler

Dans Swift 3.0 - 

Dans mon cas, je souhaitais que le VC présélectionne le texte dans un TextView et affiche un menu personnalisé pour que l'utilisateur puisse agir sur cette sélection. Comme mentionné par Kalle , l’ordre est très important, en particulier pour que setMenuVisible soit le dernier. 

Dans VC, viewDidLoad:

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

Dans VC, lorsque l'utilisateur appuie sur un bouton:

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

Enfin, dans la sous-classe de TextView:

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
    }
  }
}
0
profRic