Lorsque l'on porte une application IOS sur MacCatalyst, se pose la question du menu.
Ici je voulais ajouter un menu "Open" à mon application, mais comment faire ?
J'ai mis mon code entre "#if TARGET_OS_MACCATALYST" car ce code fonctionne aussi avec IOS el la notion de UIMenuBuilder n'apparait que dans IOS13, or je développe mes application pour IOS9 car beaucoup d'utilisateurs ont des vieux appareils...
Ici je voulais ajouter un menu "Open" à mon application, mais comment faire ?
J'ai mis mon code entre "#if TARGET_OS_MACCATALYST" car ce code fonctionne aussi avec IOS el la notion de UIMenuBuilder n'apparait que dans IOS13, or je développe mes application pour IOS9 car beaucoup d'utilisateurs ont des vieux appareils...
#if TARGET_OS_MACCATALYST
-(void)buildMenuWithBuilder:(id)builder {
NSLog(@"buildMenuWithBuilder !!");
[super buildMenuWithBuilder:builder];
if(builder.system == UIMenuSystem.mainSystem) {
[builder removeMenuForIdentifier:UIMenuFormat];
// Le menu "Format" ne m'interresse pas
// On crée la commande...
//L'action doit être une fonction déclarée dans le FirstResponder
UIKeyCommand *command_O = [UIKeyCommand
commandWithTitle:@"Import"
image:nil
action:NSSelectorFromString(@"importfile:")
input:@"O"
modifierFlags:UIKeyModifierCommand
propertyList:nil];
// On crée l'entrée du menu à partir de la commande
UIMenu *menu = [UIMenu
menuWithTitle:@"" // Inutilisé ici
image:nil // Utile que sous IOS
identifier:@"UTI unique" // Un nom unique
options:UIMenuOptionsDisplayInline
children:@[ command_O ]]; // Une seule commande
// On insert l'entrée de menu
// en première position dans le menu Fichier.
[builder insertChildMenu:menu atStartOfMenuForIdentifier:UIMenuFile];
}
}
#endif
Donc la fonction buildMenuWithBuilder: doit être ajouté dans le AppDelegate.m et contenir :
- L'appel à [super BuildMenuWithBuilder:builder]; pour que l'app crée bien le menu.
- Un test pour vérifier que l'on parle bien du menu système, et si ce n'est pas le cas ne rien faire.
- Vous pouvez supprimer des menu que vous ne voulez pas avec [builder removeMenuForIdentifier:], les menus standards ont évidemment leur constante de définit (comme ici UIMenuFormat).
- Pour chaque entrée du menu :
- On crée le UIKeyCommand qui définit quelle action va être effectuée.
- On crée le UIMenu avec UIMenuOptionDisplayInline pour une entrée simple (pas de sous menu).
- On insère le menu au début ou à la fin d'un menu déjà présent.
Voilà, le menu "Open" apparait... Mais petite remarque sur l'action de la UIKeyCommand. Vous aurez peut-être remarqué qu'il n'y a pas de Target et que j'ai utilisé NSSelectorFromString() ) la place de @selector().
En fait l'action doit être faite par le FirstResponder. C'est pourquoi on ne peut pas utilise @selector() qui est une macro du précompilateur. La fonction pointée par action n'existe pas ici dans le AppDelegate, je l'ai mise dans la classe de mon premier ViewController. Il faut donc utiliser NSSelectorFromString() pour éviter un Warning, car la fonction n'est pas visible par le compilateur.
Ce système est très intéressant car si la fonction n'est pas définie dans le FirstResponder, l'entrée dans le menu est grisée automatiquement.
Donc cas 1 :
Imaginons que vous ayez un premier ViewController qui répond à l'action open, le menu apparait actif, même si l'on passe dans un autre ViewController, l'action reste active car le FirstResponder est capable de répondre à tous les sélecteurs définis dans sa classe, mais aussi à tous les sélecteurs définis dans le ViewController parents.
Et cas 2 :
Si nous définissons notre action dans un ViewController qui n'est pas le root, ce n'est que quand notre ViewController sera actif que l'entrée de menu sera active, et elle restera active même si le ViewController présente de nouveaux ViewController. Et évidemment elle redeviendra inactive si l'on quitte le ViewController.
Commentaires