Comment est-ce que je pourrais replace UIMenuController avec ma propre vue quand le text est choisi?

Lorsque le text est sélectionné, un UIMenuController apparaît par défaut avec couper / copyr / coller, etc.

entrez la description de l'image ici

Je voudrais replace cela avec ma propre vue personnalisée (semblable, mais deux fois plus élevé de sorte que je peux avoir deux rangées de buttons / vues personnalisées). Comment puis-je faire ceci?

Je sais qu'il n'y a pas de moyen facile. Je m'attends à ce que s'il y a une solution facile, ce ne sera pas très élégant. Le code ne peut pas non plus utiliser d'API privée.

Je n'aurais vraiment pas vraiment besoin d'implémenter ma propre vue de text, de réimplémenter la sélection et la saisie de text et de réimplémenter la vue grossissante juste pour écrire mon propre clone UIMenuController s'il y a moyen de l'éviter. Il est très important pour l'interface de l'application que je puisse replace le UIMenuController, donc s'il n'y a pas d'autre réponse, je pourrais finir par le faire. Je serai très reconnaissant si quelqu'un peut me sauver un morceau décent de time et de proposer une autre, une façon plus facile de le faire!

Il y a trois choses importantes que vous devez savoir avant de pouvoir commencer:

1) Vous devrez écrire votre vue de controller de menu personnalisée, mais je suppose que vous vous y attendiez un peu. Je connais seulement une implémentation commerciale d'un controller de menu personnalisé, mais cela ne devrait pas être trop dur.

2) Il existe une méthode utile sur UIResponder appelée -canPerformAction:withSender: En savoir plus à ce sujet dans le UIResponder Class Reference . Vous pouvez utiliser cette méthode pour déterminer si votre affichage de text prend en charge une action standard spécifique (définie dans le protocole UIResponderStandardEditActions ).
Cela sera utile lorsque vous déciderez des éléments à afficher dans votre controller de menu personnalisé. Par exemple, l'élément de menu Coller ne s'affiche que lorsque le carton de l'user contient une string à coller.

3) Vous pouvez détecter quand UIMenuController sera affiché en écoutant la notification UIMenuControllerWillShowMenuNotification .

Maintenant que vous savez tout cela, voici comment je commencerais à m'y attaquer:

1) Écoutez UIMenuControllerWillShowMenuNotification s lorsque la vue text est le premier répondeur

 - (void)textViewDidBeginEditing:(UITextView *)textView { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(menuWillBeShown:) name:UIMenuControllerWillShowMenuNotification object:nil]; } - (void)textViewDidEndEditing:(UITextView *)textView { [[NSNotificationCenter defaultCenter] removeObserver:self name:UIMenuControllerWillShowMenuNotification object:nil]; } 

2) Montrez votre controller de menu personnalisé au lieu du UIMenuController par défaut

 - (void)menuWillBeShown:(NSNotification *)notification { CGRect menuFrame = [[UIMenuController sharedMenuController] menuFrame]; [[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO]; // Don't show the default menu controller CustomMenuController *controller = ...; controller.menuItems = ...; // additional stuff goes here [controller setTargetRectWithMenuFrame:menuFrame]; // menuFrame is in screen coordinates, so you might have to convert it to your menu's presenting view/window/whatever [controller setMenuVisible:YES animated:YES]; } 

Divers 1) Vous pouvez utiliser une UIWindow plein écran pour afficher votre menu personnalisé afin qu'il puisse chevaucher la barre d'état.

 UIWindow *presentingWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; presentingWindow.windowLevel = UIWindowLevelStatusBar + 1; presentingWindow.backgroundColor = [UIColor clearColor]; [presentingWindow addSubview:controller]; [presentingWindow makeKeyAndVisible]; 

Divers 2) Pour déterminer les éléments de menu à afficher, vous pouvez utiliser l' -canPerformAction:withSender:

 BOOL canPaste = [textView canPerformAction:@selector(paste:) withSender:nil]; BOOL canSelectAll = [textView canPerformAction:@selector(selectAll:) withSender:nil]; 

Divers 3) Vous devrez gérer le rejet du menu vous-même en utilisant un UITapGestureRecognizer sur la window de présentation ou quelque chose comme ça.

Ce ne sera pas facile, mais c'est faisable et j'espère que ça marche bien pour vous. Bonne chance!

Mettre à jour:
Une nouvelle implémentation de menu est apparue sur cocoacontrols.com aujourd'hui que vous voudrez peut-être consulter: https://github.com/questbeat/QBPopupMenu

Mise à jour 2:
Comme expliqué dans cette réponse, vous pouvez get le cadre du text sélectionné d'une vue de text en utilisant -caretRectForPosition:

Je pense que cela peut vous aider https://github.com/cxa/UIMenuItem-CXAImageSupport

UIMenuItem utilise UILabel pour afficher son titre, ce qui signifie que nous pouvons swizzle -drawTextInRect: pour prendre en charge l'image.

UIMenuItem + CXAImageSupport est un hack sale mais devrait être sûr dans la plupart des cas. Ne contient aucune API privée.

Faire une catégorie au lieu de sous-classr pour UIMenuItem gagne plus de flexibilité. Oui, cette catégorie peut aussi être appliquée à l'incroyable PSMenuItem!

entrez la description de l'image ici