UIMenuController не отображается
Я пытаюсь создать пользовательский UIMenuController и отобразить его в моем представлении. Вот мой код:
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];
Там нет ошибок или исключений, но контроллер меню просто не появляется.
7 ответов
Вам нужно сделать три вещи:
- Вам нужно позвонить
-becomeFirstResponder
на контроллере вида или вида. - Ваш контроллер представления или представления должен реализовать
-canBecomeFirstResponder
(возвращениеYES
). - При желании, ваш вид или контроллер представления может реализовать
-canPerformAction:action withSender:sender
показать / скрыть пункты меню в индивидуальном порядке.
Ответ упоминает три вещи, но чтобы быть разборчивыми, есть шесть:
- Обработчик меню должен быть UIView. Если это не так,
-becomeFirstResponder
выходит из строя. - Обработчик меню должен иметь
userInteractionEnabled = YES
- Обработчик меню должен находиться в иерархии представления и его
-window
свойство должно совпадать с окном для представления вinView:
аргумент. - Вам необходимо реализовать
-canBecomeFirstResponder
и вернутьсяYES
, - Вам нужно позвонить
[handler becomeFirstResponder]
до[menu setTargetRect:inView:]
называется, или последний не удастся. - Вам нужно позвонить
[menu setTargetRect:inView]
(хотя бы один раз) и[menu setMenuVisible:animated:]
,
В особенности пункты 1-3 выше меня достали. Я хотел пользовательский класс обработчика меню, который был UIResponder
во-первых, что вызвало -becomeFirstResponder
возвращать NO
; тогда это был UIView
, который потерпел неудачу, то я попытался сделать это UIButton
который работал, но только потому, что userInteractionEnabled
по умолчанию YES
для кнопок и NO
за UIView
s.
UIMenuController
отображается в любом представлении, только если оно является первым респондентом и
- (BOOL)canPerformAction
метод возвращает YES
Следовательно, если ваш контроллер меню должен отображаться при нажатии кнопки, первая строка в действии кнопки должна быть [self becomeFirstResponder]
, ПРИМЕЧАНИЕ: здесь self - это представление, которое будет представлять меню.
Если ваши меню должны отображаться при длительном нажатии, добавьте longPressGesture к UIView
и в случае длинного нажатия, прежде чем писать
[menuController setTargetRect:CGRectMake(50.0, 50.0, 0, 0) inView:self.view];
[menuController setMenuVisible:YES animated:YES];
записывать [self becomeFirstResponder];
Затем выполните шаги, упомянутые OZ.
Ниже приведен полный комментарий рабочий пример...
Просмотреть файл заголовка подкласса
#import <Foundation/Foundation.h>
@interface MenuControllerSupportingView : UIView
{
}
@end
Посмотреть исходный файл подкласса
#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;
}
просмотреть заголовочный файл контроллера
#import <UIKit/UIKit.h>
@interface ViewController1 : UIViewController
@end
просмотреть исходный файл контроллера
#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
В классе View, если вы пишете, верните YES самостоятельно в canPerformAction, вы увидите все стандартные элементы меню, такие как символ камеры, вырезание, копирование и т. Д.
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
return YES;
}
если вы хотите показать что-то вроде камеры в одиночку, то
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if(action==@selector(_insertImage:))
return YES;
else
return NO;
}
если вы хотите знать обо всех действиях, то
перейдите по ссылке
На всякий случай, если у кого-то возникла эта проблема специально (и случайным образом) с iOS6: возможно, вы захотите взглянуть на эту SO, связанную с включением Speak Selection на устройстве (Настройки -> Общие -> Специальные возможности -> Speak Selection: On). Небольшое количество моих пользователей не смогли увидеть кастом UIMenuItems
и это было причиной.
В Swift 3.0 -
В моем случае я хотел, чтобы VC предварительно выделил текст в TextView и отобразил пользовательское меню, чтобы пользователь мог выполнить действие над этим выбором. Как отметил Калле, порядок очень важен, особенно setMenuVisible
прошлой.
В ВК viewDidLoad
:
menuCont = UIMenuController.shared
let menuItem1: UIMenuItem = UIMenuItem(title: "Text", action: #selector(rtfView.textItem(_:)))
let menuItems: NSArray = [menuItem1]
menuCont.menuItems = menuItems as? [UIMenuItem]
В VC, когда пользователь нажимает кнопку:
@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)
}
Наконец, в подклассе 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
}
}
}
Может быть, потому, что CGRectMake(50.0, 50.0, 0, 0)
создает CGRect
с width = 0
а также height = 0
?
ура, Анка