Как заставить UIMenuController работать для пользовательского представления?

Я пытаюсь получить следующую работу кода:

UIMenuController * menu = [UIMenuController sharedMenuController]; [menu setTargetRect: CGRectMake(100, 100, 100, 100) inView: self.view]; [menu setMenuVisible: YES animated: YES]; 

Экземпляр меню готов, но он не отображается – ширина всегда равна нулю.

Или есть какой-то пример кода на этой UIPasteboard/UIMenuController ?

Я не смог заставить его работать, даже когда я прочитал все ваши ответы. Я представляю готовый код, который будет работать для всех.

Допустим, у нас есть class controllerа с именем Controller. Вы можете просто вставить следующий код на этот controller, чтобы меню работало над его представлением:

 - (void)loadView { [super loadView]; UILongPressGestureRecognizer *gr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)]; [self.view addGestureRecognizer:gr]; } - (void) longPress:(UILongPressGestureRecognizer *) gestureRecognizer { if ([gestureRecognizer state] == UIGestureRecognizerStateBegan) { CGPoint location = [gestureRecognizer locationInView:[gestureRecognizer view]]; UIMenuController *menuController = [UIMenuController sharedMenuController]; UIMenuItem *resetMenuItem = [[UIMenuItem alloc] initWithTitle:@"Item" action:@selector(menuItemClicked:)]; NSAssert([self becomeFirstResponder], @"Sorry, UIMenuController will not work with %@ since it cannot become first responder", self); [menuController setMenuItems:[NSArray arrayWithObject:resetMenuItem]]; [menuController setTargetRect:CGRectMake(location.x, location.y, 0.0f, 0.0f) inView:[gestureRecognizer view]]; [menuController setMenuVisible:YES animated:YES]; } } - (void) copy:(id) sender { // called when copy clicked in menu } - (void) menuItemClicked:(id) sender { // called when Item clicked in menu } - (BOOL) canPerformAction:(SEL)selector withSender:(id) sender { if (selector == @selector(menuItemClicked:) || selector == @selector(copy:)) { return YES; } return NO; } - (BOOL) canBecomeFirstResponder { return YES; } 

Что нужно сделать для того, чтобы меню работало, так это то, что firstResponder (в нашем случае наш controller – см. Строку с [self стать FirstResponder]) должен быть в состоянии стать первым респондентом (метод override canBecomeFirstResponder приводит к тому, что реализация по умолчанию возвращает NO) as - (BOOL) canPerformAction:(SEL)selector withSender:(id) sender который должен возвращать YES для любого действия, которое может быть выполнено firstResponder

Если вы реализуете пользовательское представление, и предполагается, что представление должно быть ответчиком (в отличие от какого-либо другого представления, например UITextField), вам нужно переопределить функцию canBecomeFirstResponder в вашем представлении и вернуть YES:

 - (BOOL)canBecomeFirstResponder { return YES; } 

затем, когда вы показываете меню, вы должны сделать что-то вроде следующего:

 - (void)myMenuFunc { if (![self becomeFirstResponder]) { NSLog(@"couldn't become first responder"); return; } UIMenuController *theMenu = [UIMenuController sharedMenuController]; CGRect selectionRect = CGRectMake(0, 0, 0, 0); [theMenu setTargetRect:selectionRect inView:self]; [theMenu setMenuVisible:YES animated:YES]; } 

В случае, если у кого-то еще есть проблемы: мое меню использовалось для работы и в какой-то день прекратило работать чудесным образом. Все остальное в моем приложении все еще работало. Теперь я удалил метод [window makeKeyAndVisible] из application:didFinishLaunchingWithOptions: method, и пока все остальное все еще работает, это прерывает UIMenuController !

Глупая ошибка на моей стороне, трудно найти виновника …

для отображения UIMenuController необходимо добавить следующие

 - (BOOL)canPerformAction:(SEL)action withSender:(id)sender { if (action == @selector(cut:)) return NO; else if (action == @selector(copy:)) return YES; else if (action == @selector(paste:)) return NO; else if (action == @selector(select:) || action == @selector(selectAll:)) return NO; else return [super canPerformAction:action withSender:sender]; } 

Я думаю, что Cam прав, нужно переопределить как canPerformAction, так и canBecomeFirstResponder

 - (BOOL) canPerformAction:(SEL)action withSender:(id)sender { if (action == @selector(doSomething:)) { return YES; } return NO; } - (BOOL)canBecomeFirstResponder { return YES; } 
 // MyView.h @interface MyView : UIView { IBOutlet UITextField * textField_; } @end // MyView.m - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ NSLog(@"show menu"); [textField_ becomeFirstResponder]; // [self.window becomeFirstResponder]; UIMenuController * menu = [UIMenuController sharedMenuController]; [menu setTargetRect: CGRectMake(0, 0, 100, 10) inView: self]; [menu setMenuVisible: YES animated: YES]; NSLog(@"menu width %f, visible %d", menu.menuFrame.size.width, menu.menuVisible); } - (BOOL)canPerformAction:(SEL)action withSender:(id)sender{ return YES; } 

Вам нужно добавить еще один код в canPerformAction: withSender: – он должен проверить картон и ваше состояние выбора. Руководство Apple по программированию приложений Apple содержит несколько fragmentов кода.

Вам не нужно добавлять UIMenuController* menu в основное или подчиненное, EG self.view ? Я думаю, что это что-то вроде [self.view addSubView:menu.view]; Или я пропущу точку вашего вопроса. Вы также можете установить рамку просмотра меню.

У UIMenuController нет представления. Я просто искал какой-то код из руководства Apple по программированию приложений iPhone: Обработка событий :

Листинг 3-4 Отображение меню редактирования

 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *theTouch = [touches anyObject]; if ([theTouch tapCount] == 2 && [self becomeFirstResponder]) { // selection management code goes here... // bring up editing menu. UIMenuController *theMenu = [UIMenuController sharedMenuController]; CGRect selectionRect = CGRectMake(currentSelection.x, currentSelection.y, SIDE, SIDE); [theMenu setTargetRect:selectionRect inView:self]; [theMenu setMenuVisible:YES animated:YES]; } } 

Я сделал это следующим образом. Просто вызовите метод, который показывает меню после очень короткой задержки в init. Я не хотел вызывать его из View Controller, а также не нашел событие, которое указывает, что появилось мое собственное представление, и я готов показать меню. Так что с моей точки зрения. Задержка может быть меньше, но это зависит от вас.

 @implementation DTSignatureImageView - (id)initWithImage:(UIImage *)image { self = [super initWithImage:image]; if(self){ self.contentMode = UIViewContentModeScaleAspectFit; self.frame = CGRectMake(0, 0, image.size.width / 2.5, image.size.height / 2.5); self.userInteractionEnabled = YES; UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(signatureDidPan:)]; [self addGestureRecognizer:pan]; [self becomeFirstResponder]; [self performSelector:@selector(showMenu) withObject:nil afterDelay:0.5]; } return self; } - (BOOL)canBecomeFirstResponder { return YES; } - (void)showMenu { UIMenuController *menu = [UIMenuController sharedMenuController]; menu.menuItems = @[ [[UIMenuItem alloc] initWithTitle:@"Apply" action:@selector(applySignature)], [[UIMenuItem alloc] initWithTitle:@"Update" action:@selector(updateSignature)], [[UIMenuItem alloc] initWithTitle:@"Clear" action:@selector(delegateSignature)]]; [menu setTargetRect:self.bounds inView:self]; [menu setMenuVisible:YES animated:YES]; } - (NSArray *)menuActions { static NSArray *actions = nil; if (actions == nil){ actions = @[ NSStringFromSelector(@selector(applySignature)), NSStringFromSelector(@selector(updateSignature)), NSStringFromSelector(@selector(delegateSignature))]; } return actions; } - (void) signatureDidPan: (UIPanGestureRecognizer *)gesture { switch (gesture.state) { case UIGestureRecognizerStateBegan: { [[UIMenuController sharedMenuController] setMenuVisible:NO animated:YES]; break; } case UIGestureRecognizerStateEnded: { [self becomeFirstResponder]; [self showMenu]; } default: break; } CGPoint point = [gesture locationInView:gesture.view.superview]; gesture.view.center = point; } 
Давайте будем гением компьютера.