Отображение UIMenuController теряет клавиатуру

Я делаю приложение для iphone, похожее на приложение «Сообщения», которое есть на телефоне. Я просто настроил возможность копировать сообщения через UIMenuController, но если клавиатура отображается и кто-то пытается скопировать сообщение, клавиатура исчезает (предположительно из-за моего [cell becomeFirstResponder];, где cell — копируемая ячейка сообщения).

Есть ли способ показать сообщение «Копировать» без потери клавиатуры?

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
(NSIndexPath *)indexPath {

    //...other cell setup stuff...

    UILongPressGestureRecognizer *longPressGesture =
    [[UILongPressGestureRecognizer alloc]
      initWithTarget:self action:@selector(showCopyDialog:)];
    [cell addGestureRecognizer:longPressGesture];

    return cell;
}

- (void)showCopyDialog:(UILongPressGestureRecognizer *)gesture
{
    if (gesture.state == UIGestureRecognizerStateBegan)
    {
        ConvoMessageCell *cell = (ConvoMessageCell *)[gesture view];
        NSIndexPath *indexPath = [self.tblConvo indexPathForCell:cell];

        UIMenuController *theMenu = [UIMenuController sharedMenuController];
        [cell becomeFirstResponder];
        [theMenu setTargetRect:CGRectMake(menuX, menuY, 100, 100) inView:cell];
        [theMenu setMenuVisible:YES animated:YES];        
    }
}

person Stephen    schedule 05.12.2011    source источник


Ответы (2)


Я решил эту дилемму, создав подкласс UITextView, чтобы предоставить способ переопределить nextResponder и отключить встроенные действия (Paste), например:

@interface CustomResponderTextView : UITextView

@property (nonatomic, weak) UIResponder *overrideNextResponder;

@end

@implementation CustomResponderTextView

@synthesize overrideNextResponder;

- (UIResponder *)nextResponder {
    if (overrideNextResponder != nil)
        return overrideNextResponder;
    else
        return [super nextResponder];
}

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    if (overrideNextResponder != nil)
        return NO;
    else
        return [super canPerformAction:action withSender:sender];
}

@end

Затем в обработчике жестов проверьте, не является ли текстовое представление первым ответчиком. Если это так, пусть он переопределит следующего ответчика; в противном случае клавиатура, вероятно, все равно скрыта, и вы можете просто becomeFirstResponder. Вам также придется сбросить переопределение, когда меню скроется:

if ([inputView isFirstResponder]) {
    inputView.overrideNextResponder = self;
    [[NSNotificationCenter defaultCenter] addObserver:self
        selector:@selector(menuDidHide:)
        name:UIMenuControllerDidHideMenuNotification object:nil];
} else {
    [self becomeFirstResponder];
}

- (void)menuDidHide:(NSNotification*)notification {

    inputView.overrideNextResponder = nil;
    [[NSNotificationCenter defaultCenter] removeObserver:self
        name:UIMenuControllerDidHideMenuNotification object:nil];
}

Использование методов делегата табличного представления, представленных в iOS 5 (shouldShowMenuForRowAtIndexPath и т. д.), не было для меня решением, поскольку мне нужно было контролировать позиционирование меню (по умолчанию оно просто горизонтально центрировано над ячейкой, но я показываю всплывающие сообщения и хотел, чтобы меню было сосредоточено над настоящим пузырем).

person neon1    schedule 10.11.2012
comment
Отличный ответ, спасибо! любая библиография для этого? - person AmitP; 12.02.2014
comment
Это работает отчасти. Появляющийся MenuController принадлежит CustomResponderTextView, а не ячейке. Есть идеи, как это исправить? - person Takeshi Kaga; 30.10.2015

В iOS 5 теперь вы можете использовать методы делегата табличного представления для отображения контроллера меню:

- (BOOL) tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath

- (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender;

- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender;

Отображение контроллера меню таким образом не откажется от клавиатуры.

Мне все еще любопытно это, поскольку у меня есть приложение, которое поддерживает пред-iOS 5, и я хотел бы также делать то, что вы говорите (не отказываться от клавиатуры, когда появляется меню копирования).

person Keller    schedule 02.03.2012
comment
Это может сработать, но MenuController будет размещен прямо в горизонтальном центре ячейки. - person Takeshi Kaga; 30.10.2015