Клавиатура iPad не будет отклоняться, если модальный стиль представления ViewController - UIModalPresentationFormSheet

214

Примечание:

См. Принятый ответ (не с наибольшим количеством голосов) для решения от iOS 4.3.

Этот вопрос о поведении, обнаруженном на клавиатуре iPad, когда он отказывается отклоняться, если отображается в модальном диалоге с контроллером навигации.

В основном, если я представлю навигационный контроллер со следующей строкой, как показано ниже:

navigationController.modalPresentationStyle = UIModalPresentationFormSheet;

Клавиатура отказывается отмахиваться. Если я закомментирую эту строку, клавиатура исчезнет нормально.

...

У меня есть два textFields, имя пользователя и пароль; имя пользователя имеет кнопку «Далее», а пароль - кнопку «Готово». Клавиатура не исчезнет, ​​если я представлю это в модальном навигационном контроллере.

РАБОТАЕТ

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
[self.view addSubview:b.view];

НЕ РАБОТАЕТ

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
UINavigationController *navigationController = 
[[UINavigationController alloc]
 initWithRootViewController:b];
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
navigationController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:navigationController animated:YES];
[navigationController release];
[b release];

Если я удаляю часть контроллера навигации и представляю «b» как модальный контроллер вида, он работает. Проблема с навигационным контроллером?

РАБОТАЕТ

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
b.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:b animated:YES];
[b release];

РАБОТАЕТ

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
UINavigationController *navigationController = 
    [[UINavigationController alloc]
         initWithRootViewController:b];
[self presentModalViewController:navigationController animated:YES];
[navigationController release];
[b release];
Kalle
источник
Следующий вопрос SO, похоже, имеет ту же проблему, но ответов нет: stackoverflow.com/questions/3019709/…
Kalle
+1 Спасибо за ваше великолепное объяснение. Но где я должен поместить этот метод? Кажется, не работает, где я создаю код для представления модели контроллера ...
Lorenzo B
1
Он должен быть в самом классе контроллера модального вида.
Калле
Спасибо. Понимаю. Я решил положить его в категорию для UINavigationControllerкласса. Приветствия.
Лоренцо Б
Я так обязан вам за этот вопрос. Я был удивлен, что resignFirstResponderвыполнялся, но клавиатура все еще показывалась. Мой сценарий (presentationFormSheet с навигационным контролем) точно такой же, как ваш. Благодаря тонну!!
sErVerdevIL

Ответы:

115

В контроллере представления, который представлен модально, просто переопределите, disablesAutomaticKeyboardDismissalчтобы возвратить NO:

- (BOOL)disablesAutomaticKeyboardDismissal {
    return NO;
}
Себастьян Н
источник
Да, начиная с 4.3, похоже, это так. Буду обновлять вопрос. Спасибо!
Калле
2
Это нужно добавить в навигационный контроллер
pottedmeat
1
Да, работает, когда вы перезаписываете его в NavigationController. Это единственное, что действительно работает для меня.
Джеймс Лоренстин
Спасатель жизни! Почему Apple делает такие вещи? Конечно, по умолчанию он должен быть «Нет» и позволить нам изменить его, если мы действительно этого хотим
SomaMan
Не работает с классом, производным от UIViewController, отключение AutoMateKeyboardDismissal никогда не вызывается
Хорхе Аримани
172

Это было классифицировано инженерами Apple как «работа по назначению». Я подал ошибку для этого некоторое время назад. Их аргументация заключается в том, что пользователь часто собирается вводить данные в модальной форме, поэтому они пытаются быть «полезными» и держать клавиатуру видимой, где обычно различные переходы в модальном представлении могут вызывать многократное отображение / скрытие клавиатуры.

редактировать: вот ответ инженера Apple на форумах разработчиков:

Был ли ваш взгляд случайно представлен в стиле UIModalPresentationFormSheet? Чтобы избежать частых анимаций ввода-вывода, клавиатура иногда остается на экране, даже если нет первого респондента. Это не ошибка.

Это создает проблемы для многих людей (включая меня), но на данный момент, похоже, нет способа обойти это.

ОБНОВИТЬ:

В iOS 4.3 и более поздних версиях вы можете теперь реализовать `-disablesAutomaticKeyboardDismissal 'на вашем контроллере представления, чтобы вернуть NO:

- (BOOL)disablesAutomaticKeyboardDismissal {
    return NO;
}

Это решает проблему.

Майк Веллер
источник
7
пауза Вау, хорошо. Большое спасибо за заголовки. Черт, Яблоко .. :(
Калле
Вы отправили отчет об ошибке в Apple? Я сделал это под идентификатором № 8384423. Я также представил образец приложения для воспроизведения поведения.
Лохматая лягушка
3
Начиная с iOS 4.3 теперь есть метод disablesAutomaticKeyboardDismissal, который решает эту проблему.
Калле
5
я пытаюсь, что отключает метод AutoKeyboardDismissal, но это все еще не решило проблему, как ее решить?
Р. Деви
3
@Snips: вам нужно создать UINavigationControllerподкласс, который переопределяет disablesAutomaticKeyboardDismissalдля возврата NOи использовать его в качестве контроллера навигации, когда вы представляете модальную форму листа. Смотрите ответ от @ miha-hribar ниже.
Паскаль
149

Будьте осторожны, если вы отображаете модал с UINavigationController. Затем вы должны установить disablesAutomaticKeyboardDismissalна контроллере навигации, а не на контроллере представления. Вы можете легко сделать это с категориями.

Файл: UINavigationController + KeyboardDismiss.h

#import <Foundation/Foundation.h>

@interface UINavigationController (KeyboardDismiss)

- (BOOL)disablesAutomaticKeyboardDismissal;

@end

Файл: UINavigationController + KeyboardDismiss.m

#import "UINavigationController+KeyboardDismiss.h"

@implementation UINavigationController(KeyboardDismiss)

- (BOOL)disablesAutomaticKeyboardDismissal
{
    return NO;
}

@end

Не забудьте импортировать категорию в файл, где вы используете UINavigationController.

Миха Хрибар
источник
19
+1, наконец , я вижу недостающую часть информации по этому вопросу отметил: что нужно переопределить disablesAutomaticKeyboardDismissalиз UINavigationController, а не собственного контроллера представления, чтобы устранить эту проблему.
DarkDust
Ницца! Как раз то, что мне было нужно. Спасибо.
Джастин
Отлично. Не ясно из официальных документов, но имеет смысл, поскольку UINavigationController находится в цепочке респондента. Отличный ответ. Спасибо!
imnk
1
Я представляю модальный диалог из UISplitViewController. Я пробовал приведенный выше код, но заменил UISplitViewController на UINavigationController, но он все равно не работает. Должен ли этот метод также работать на UISplitViewController?
Снипс
6
Не стоит внедрять дубликат метода в категории. Вы никогда не можете быть уверены, какая реализация будет вызвана, поэтому в лучшем случае вы можете ожидать противоречивого поведения. Лучше наследовать от UINavigationController и переопределить метод в вашем пользовательском классе.
Шон Вудворд,
51

Я решил это, используя UIModalPresentationPageSheetстиль презентации и изменив его размер сразу же после его представления. Вот так:

viewController.modalPresentationStyle = UIModalPresentationPageSheet;
viewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:viewController animated:YES];
viewController.view.superview.autoresizingMask = 
    UIViewAutoresizingFlexibleTopMargin | 
    UIViewAutoresizingFlexibleBottomMargin;    
viewController.view.superview.frame = CGRectMake(
    viewController.view.superview.frame.origin.x,
    viewController.view.superview.frame.origin.y,
    540.0f,
    529.0f
);
viewController.view.superview.center = self.view.center;
[viewController release];
azdev
источник
Хммм ... это не совсем правильно ... изменение размера заставляет модал рисовать смешно ... это как будто он сдавливает содержимое, чтобы поместиться в новый размер или что-то в этом роде ... все выглядит забавно. :(
Toofah
Также есть проблемы с вращением ... если вы вращаете, когда этот модал работает, он будет уменьшаться / увеличиваться, как если бы это был полный просмотр страницы
toofah
2
Toofah, я редактировал код, чтобы справиться с проблемой сжатия / роста при вращении; только вопрос придания суперпредставлению гибкого верхнего и нижнего полей. Я не уверен, что вижу другое поведение.
Аздев
1
это работает только до тех пор, пока вы не выдвигаете другой вид поверх этого. Потому что, когда вы закрываете представление, помещенное над представленным представлением UIModalPresentationPageSheet, оно возвращается к исходному размеру.
V1ru8
Это сработало. Но слово в представлении выглядит немного размытым. Я не знаю почему.
Иисус
1

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

Было бы замечательно, если бы было исправление, но пока это работает. Вы можете включить его в категорию UIViewControllerи вызвать, когда вы хотите, чтобы клавиатура исчезла:

@interface _TempUIVC : UIViewController
@end

@implementation _TempUIVC
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return YES;
}
@end

@implementation UIViewController (Helpers)

- (void)_dismissModalViewController {
    [self dismissModalViewControllerAnimated:NO];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil];
    [self release];
}

- (void)forceKeyboardDismissUsingModalToggle:(BOOL)animated {
    [self retain];
    _TempUIVC *tuivc = [[_TempUIVC alloc] init];
    tuivc.modalPresentationStyle = UIModalPresentationCurrentContext;
    [self presentModalViewController:tuivc animated:animated];
    if (animated) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_dismissModalViewController) name:UIKeyboardDidHideNotification object:nil];
    } else
        [self _dismissModalViewController];
    [tuivc release];
}

@end

Будьте осторожны с этим, хотя, когда вы просматриваетеDidAppear / viewDidDisappear и все эти методы вызываются. Как я уже сказал, это не красиво, но работает.

-Адам

Адам
источник
1

Вы также можете обойти это в универсальном приложении, просто проверив идиому и, если это iPad, вообще не поднимайте клавиатуру и позволяйте пользователю нажимать на то, что он хочет редактировать.

Возможно, это не самое удачное решение, но оно очень простое и не требует каких-либо хитроумных хаков, которые сломаются со следующим крупным выпуском iOS :)

Maciej Swic
источник
1

Поместите этот код в ваш viewWillDisappear: метод текущего контроллера - это еще один способ исправить это:

Class UIKeyboardImpl = NSClassFromString(@"UIKeyboardImpl");
id activeInstance = [UIKeyboardImpl performSelector:@selector(activeInstance)];
[activeInstance performSelector:@selector(dismissKeyboard)];
История
источник
1

Я обнаружил, что disablesAutomaticKeyboardDismissalдобавление disablesAutomaticKeyboardDismissalфункции не работает для моегоUITextField в модальном диалоге.

Экранная клавиатура просто не исчезнет.

Мое решение состояло в том, чтобы отключить все элементы управления вводом текста в моем диалоговом окне, а затем снова включить соответствующие элементы через доли секунды.

Кажется, что , когда IOS видит , что ни один из UITextFieldэлементов управления не включен, то он действительно избавиться от клавиатуры.

Майк Гледхилл
источник
0

Я уверен, что вы смотрели на это, но вы уверены, что ваш класс контроллера правильно подключен как делегат UITextField, верно?

Нил Л
источник
Я установил это вручную, и методы делегата вызваны, так что да.
Калле
0

Может быть , не вернуть НЕТ, но ДА. Так что это может уйти.

И у вас есть textFieldShouldEndEditingвозвращение да?

И почему ты стреляешь [nextResponder becomeFirstResponder]?! извини я вижу сейчас

У меня также есть несколько UITextViews, у каждого из которых свойство "editable" установлено в FALSE.

Можем ли мы предположить, что ни один из них, случайно, не имеет tagзначения secondField.tag+1? Если это так, вы говорите им стать первым респондентом, а не уходить в отставку первым. Возможно, поместите NSLog () в структуру if.

MVDS
источник
1
НЕТ = не вставлять перевод строки, насколько я могу судить. И установка на ДА не исправила это.
Калле
1
Я думаю, что UITextField, будучи одной строкой по определению, мало что делает с символами новой строки. Так что больше об обработке нажатия кнопки Return / Done, как указано в документации.
mvds
Вы уверены, что все правильно подключили? Вы вставили NSLog("tf %x / method ...",textField);во все функции делегата?
MVDS
Что ж, функции делегата вызываются надлежащим образом, и их не было бы, если бы делегат не был настроен должным образом. И NSLog дает EXC_BAD_ACCESS. Также предупреждает меня о несовместимости типов в XCode.
Калле
D'о. Извините, я сам это видел. Я обновил ответ, приведенный выше, с результатами этих NSLogs, так как форматирование сработает само в комм ..
Kalle
0

Для тех, у кого проблемы с UINavigationController, смотрите мой ответ на похожий вопрос здесь: https://stackoverflow.com/a/10507689/321785

Редактировать: я считаю это улучшением решения Михаа Хрибара (поскольку решение принимается там, где оно должно быть), а не комментарием Паскаля относительно категории на UIViewController

Крис Трейхи
источник
0

может быть не идеальным решением, но работает
[self.view endEditing: YES];
от того, где ваша кнопка или жест реализован, чтобы представить модальный

Танудж Ягоори
источник
0
Swift 4.1:
extension UINavigationController {
   override open var disablesAutomaticKeyboardDismissal: Bool {
      return false
   }
}
fivewood
источник