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.
Vous devez faire trois choses:
-becomeFirstResponder
sur la vue ou le contrôleur de vue.-canBecomeFirstResponder
(en retournant YES
).-canPerformAction:action withSender:sender
pour afficher/masquer les éléments de menu individuellement.La réponse mentionne trois choses, mais pour être difficile, il y en a six:
-becomeFirstResponder
échoue.userInteractionEnabled = YES
-window
doit être identique à la fenêtre de la vue dans l'argument inView:
.-canBecomeFirstResponder
et renvoyer YES
.[handler becomeFirstResponder]
, avant que le[menu setTargetRect:inView:]
soit appelé, sinon ce dernier échouera.[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 UIView
s.
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.
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
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.
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
}
}
}