Простой способ уволить клавиатуру?


377

У меня довольно много элементов управления, разбросанных по многим ячейкам таблицы в моей таблице, и мне было интересно, есть ли более простой способ уволить клавиатуру без необходимости циклически перебирать все мои элементы управления и отказываться от них всех в качестве первого респондента. Я предполагаю, что вопрос .. Как бы я получить текущий первый ответчик на клавиатуре?


хорошее дополнение к этому вопросу: stackoverflow.com/questions/1490573/…
— ericsoco

Предостережение ко всем ответам ниже. Если вы выполните переход сразу после того, как вы уйдете в отставку, KB становится потерянным и не может быть отклонен. Вы должны удалить КБ в методе textFieldShouldReturn.
— GJPC

26
глобальное увольнение с клавиатуры правильным способом:[[[UIApplication sharedApplication] keyWindow] endEditing:YES];
— Йерк

Я нашел это видео полезным pinkstone.co.uk/… . Может быть, это может помочь другим.
— энтузиастик

Ответы:


797

Пытаться:

[self.view endEditing:YES];

1
Это похоже на работу (проверено на ios4.1). Хотя он доступен только на iOS 3.2 и выше. Я не уверен, гарантированно ли это работает, или это просто не гарантированный побочный эффект от вызова API способом, который не задокументирован для работы.
— Иосиф,

3
Это отлично сработало для меня, и, безусловно, предпочтительнее других ответов на этот вопрос. Документы говорят, что это доступно в iOS 2.0 и позже.
— рассвета

8
Как сказано в документации: «Этот метод просматривает текущее представление и его иерархию подпредставления для текстового поля, которое в настоящий момент является первым респондентом. Если он находит его, он просит это текстовое поле подать в отставку как первый респондент. Если установлен параметр force к ДА, текстовое поле никогда даже не спрашивается; оно вынуждено уйти в отставку. " - так что это IMO правильный ответ на исходный вопрос (вариант использования: у меня есть форма с миллионами полей, ну - десять ... или около того, и мне нужно отклонить клавиатуру).
— Джоши

14
Ответ не является неправильным, но немного неправильным, на самом деле это должно быть так: [self.view endEditing:YES];значения BOOL - это ДА / НЕТ в Objective-C.
— Крисбен

24
chrisben: Вы можете использовать ДА / НЕТ, ИСТИНА / ЛОЖЬ, 0/1.
— Майкл Суперчински

126

Вы можете заставить текущее редактируемое представление изменить статус первого респондента с помощью [view endEditing:YES]. Это скрывает клавиатуру.

В отличие от -[UIResponder resignFirstResponder], -[UIView endEditing:]будет искать через подпредставления, чтобы найти текущий первый респондент. Таким образом, вы можете отправить его на верхний уровень представления (например, self.viewв UIViewController), и он будет делать правильные вещи.

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


Но это только блокирует превращение компонента в firstResponder, но не удаляет текущее состояние firstResponder из элемента.
— Кендалл Хельмштеттер Гелнер

Что я имел в виду, переопределив становление стал одним из первых респондентов, чтобы где-то хранить первый респондент, чтобы к нему можно было получить доступ (в данном случае отказался) позже. Основная проблема заключается в том, что Cocoa Touch не предоставляет способ спросить у окна или посмотреть, каков его первый респондент.
— Николас Райли

+1 При добавленииенефилдРеспондер решены проблемы, которые у меня возникали с касаниями других полей UITextField.
— Джейсон Джордж

3
Это устарело. [self.view endEditing:YES];Ответ лучше.
— фтв

1
Это не устарело, этот ответ объясняет, как именно [UIView endediting:]работает. В одном из приложений, которые я разработал, в UINavigationViewController было добавлено поле поиска, если вы просто вызовете его [self.view endEditing:YES]как selfконтроллер представления, это не будет работать, вместо этого я вызвал этот метод непосредственно в области просмотра, где было добавлено поле поиска, например: [self.mySearchBoxView endEditing:YES],
— Ян Кассио

92

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

Objective-C:

[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];

Swift 3.0:

UIApplication.shared.sendAction(#selector(resignFirstResponder), to: nil, from: nil, for: nil)

Действия с нулевым таргетингом распространены в Mac OS X для команд меню, и вот их использование в iOS.


14
Лучшее решение всей страницы.
— Лев Натан

Абсолютно лучший способ избавиться от клавиатуры из любого приложения iOS.
— Бен Синклер

У меня все еще работает в iOS8. В моем приложении у меня есть меню боковой панели, и есть моменты, когда «центральный» контроллер вида показывает клавиатуру. И я хочу отклонить клавиатуру, если появится меню боковой панели. Поэтому я добавил этот код в метод меню Class 'viewWillAppear моего бокового меню.
— Дженн Ив

1
По-прежнему работает в iOS 9. Отличный способ глобально сместить фокус текстового поля и закрыть клавиатуру.
— bmjohns

И чтобы продолжить эту конкретную серию комментариев ... Все еще работает в iOS 10. :-)
— Путешествующий человек

56

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

  1. В viewDidLoad зарегистрируйтесь для получения уведомлений клавиатуры и создайте UITapGestureRecognizer:

    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    
    [nc addObserver:self selector:@selector(keyboardWillShow:) name:
    UIKeyboardWillShowNotification object:nil];
    
    [nc addObserver:self selector:@selector(keyboardWillHide:) name:
    UIKeyboardWillHideNotification object:nil];
    
    tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
    action:@selector(didTapAnywhere:)];
  2. Добавить клавиатуру показать / скрыть респондентов. Там вы добавляете и удаляете TapGestureRecognizer в UIView, который должен отпускать клавиатуру при нажатии. Примечание. Нет необходимости добавлять его во все вложенные представления или элементы управления.

    -(void) keyboardWillShow:(NSNotification *) note {
        [self.view addGestureRecognizer:tapRecognizer];
    }
    
    -(void) keyboardWillHide:(NSNotification *) note
    {
        [self.view removeGestureRecognizer:tapRecognizer];
    }
  3. TapGestureRecognizer будет вызывать вашу функцию, когда он получает нажатие, и вы можете отклонить клавиатуру следующим образом:

    -(void)didTapAnywhere: (UITapGestureRecognizer*) recognizer {    
        [textField resignFirstResponder];
    }

Хорошая особенность этого решения заключается в том, что оно фильтрует только касания, а не считывания. Поэтому, если у вас есть прокрутка контента над клавиатурой, пролистывание все равно будет прокручиваться и клавиатура будет отображаться. Удалив распознаватель жестов после того, как клавиатура исчезнет, ​​будущие касания на вашем экране обрабатываются как обычно.


К своему @implementation я добавил @property (назначить) UITapGestureRecognizer * tapRecognizer; и измененный self.tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector (didTapAnywhere :)];
— Профессор Тодд

Я пытаюсь сделать аналогичную вещь, и я не получаю обратного вызова на кране. Любопытно: почему ваша собственность «назначается»?
— TahoeWolverine

Плюс один, и, кроме того, это должно быть поведение iOS по умолчанию. Или, по крайней мере, добавить простой способ переключения кнопки отклонения.
— Шаунти Фондриси,

24

Это решение, позволяющее убрать клавиатуру при попадании returnв любое текстовое поле путем добавления кода в одном месте (поэтому не нужно добавлять обработчик для каждого текстового поля):


рассмотрим этот сценарий:

У меня есть viewcontrollerс двумя текстовыми полями (имя пользователя и пароль). и viewcontrollerреализует UITextFieldDelegateпротокол

я делаю это в viewDidLoad

- (void)viewDidLoad 
{
    [super viewDidLoad];

    username.delegate = self;
    password.delegate = self;
}

и viewcontroller реализует необязательный метод как

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    [textField resignFirstResponder];
    return YES;
}

и независимо от того, в каком текстовом поле вы находитесь, как только я нажму returnна клавиатуре, оно будет отклонено!

В вашем случае то же самое будет работать, если вы установите для всех делегатов текстового поля значение self и реализуете textFieldShouldReturn


Ну, у меня уже есть проблема решена, но в моем случае я хотел убрать клавиатуру самостоятельно (в коде), и я не знал, какой textField имел статус первого респондента.
— Семьдесят

1
Существуют случаи, когда вы можете захотеть отклонить клавиатуру, не нажимая «возврат», например, когда собирается появиться боковое меню
— Питер Джонсон,

Отредактировано, чтобы уточнить, что этот ответ уместен только в ситуациях, когда нажатие «возврата» является приемлемым решением. [В моем случае я также хотел отклонить клавиатуру, когда пользователь нажимает за пределы редактируемого поля; этот ответ не поможет с этим].
— ToolmakerSteve

14

Лучше всего, чтобы что-то «украло» статус первого респондента.

Поскольку UIApplication является подклассом UIResponder, вы можете попробовать:

[[UIApplication sharedApplication] becomeFirstResponder]
[[UIApplication sharedApplication] resignFirstResponder]

В противном случае создайте новый UITextField с фреймом нулевого размера, добавьте его где-нибудь в представление и сделайте что-то подобное (переходите в отставку).


1
Трюк с UIApplication не работает (он падает, по крайней мере, на симуляторе), но вам не нужен UITextField нулевого размера - просто выберите любое случайное поле и сделайте это с ним. NSResponder, являющийся становлениемFirstResponder, является методом только уведомления, но UIResponder не является (фактически, дизайн хуже).
— Николас Райли

1
Ага, спасибо! Он вылетает, вызывая его в UIApplication, но UITextField нулевого размера прекрасно работает, и мне не нужно получать какие-либо из моих предыдущих полей.
— Семьдесят

Зачем кому-то делать это, если есть официальный, совершенно хороший и документированный метод для этого?
— Maciej Swic

2
Они не будут, увидеть большинство проголосовавших ответ для лучшего решения. В то время он был не очень известен (мой ответ был с 2009 года, другой ответ пришел более чем через год в 2010 году). но я оставляю это для потомков.
— Кендалл Хельмштеттер Гелнер

8

Уберите это в некотором служебном классе.

+ (void)dismissKeyboard {
    [self globalResignFirstResponder];
}

+ (void) globalResignFirstResponder {
    UIWindow * window = [[UIApplication sharedApplication] keyWindow];
    for (UIView * view in [window subviews]){
        [self globalResignFirstResponderRec:view];
    }
}

+ (void) globalResignFirstResponderRec:(UIView*) view {
    if ([view respondsToSelector:@selector(resignFirstResponder)]){
        [view resignFirstResponder];
    }
    for (UIView * subview in [view subviews]){
        [self globalResignFirstResponderRec:subview];
    }
}

1
это то, что я искал!
— aslisabanci

Отлично, за исключением того, что вам вообще не нужен метод globalResignFirstResponderRec, просто вызовите [view endEditing: YES]. Это делает то же самое.
— 13

Да! Окончательное решение! Я пробовал много способов, только этот работает для меня! Большое спасибо!
— Douyw

6

@ Николас Райли & @Kendall Helmstetter Geln & @cannyboy:

Абсолютно блестящий!

Спасибо.

Учитывая ваши советы и советы других в этой теме, вот что я сделал:

Как это выглядит при использовании:

[[self appDelegate] dismissKeyboard]; (примечание: я добавил appDelegate как дополнение к NSObject, чтобы я мог использовать где угодно и что угодно)

Как это выглядит под капотом:

- (void)dismissKeyboard 
{
    UITextField *tempTextField = [[[UITextField alloc] initWithFrame:CGRectZero] autorelease];
    tempTextField.enabled = NO;
    [myRootViewController.view addSubview:tempTextField];
    [tempTextField becomeFirstResponder];
    [tempTextField resignFirstResponder];
    [tempTextField removeFromSuperview];
}

РЕДАКТИРОВАТЬ

Поправка к моему ответу включена tempTextField.enabled = NO;. Отключение текстового поля будет препятствовать UIKeyboardWillShowNotificationи UIKeyboardWillHideNotificationклавиатуры уведомления от отправки вы должны полагаться на эти уведомления по всему приложению.


я не знаю, работает ли это, но это кажется разумным и простым способом.
— демон

5

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

Вот ссылка


Большой! добавление в AppDelegate заставляет его работать для ВСЕХ связанных представлений.
— Цзюлун Чжао

5

Здесь много слишком сложных ответов, возможно, потому, что это не так легко найти в документации iOS. Иосиф-Х имел это прямо выше:

[[view window] endEditing:YES];

4

Даже проще, чем ответ Мигар

перезапись touchesBegan:withEvent:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [textField resignFirstResponder];`
}

Это будет, dismiss the keyboardкогда вы касаетесь в любом месте background.


3

Вот что я использую в своем коде. Работает как часы!

В yourviewcontroller.h добавьте:

@property (nonatomic) UITapGestureRecognizer *tapRecognizer;

Теперь в .m файле добавьте это к вашей функции ViewDidLoad:

- (void)viewDidLoad {
    //Keyboard stuff
    tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapAnywhere:)];
    tapRecognizer.cancelsTouchesInView = NO;
    [self.view addGestureRecognizer:tapRecognizer];
}

Также добавьте эту функцию в файл .m:

- (void)handleSingleTap:(UITapGestureRecognizer *) sender
{
    [self.view endEditing:YES];
}

Спасибо! Но вы должны переименовать функцию в didTapAnywhere или в распознаватель жестов в handleSingleTap ;-)
— Matthijs

2

В заголовочном файле контроллера вашего представления добавьте <UITextFieldDelegate>определение интерфейса вашего контроллера, чтобы он соответствовал протоколу делегата UITextField ...

@interface someViewController : UIViewController <UITextFieldDelegate>

... В файле реализации контроллера (.m) добавьте следующий метод или код внутри него, если у вас уже есть метод viewDidLoad ...

- (void)viewDidLoad
{
    // Do any additional setup after loading the view, typically from a nib.
    self.yourTextBox.delegate = self;
}

... Затем свяжите yourTextBox с вашим фактическим текстовым полем

- (BOOL)textFieldShouldReturn:(UITextField *)theTextField 
{
    if (theTextField == yourTextBox) {
        [theTextField resignFirstResponder];
    }
    return YES;
}

2

Вы должны отправить endEditing:в рабочее окно, являющееся подклассомUIView

[[UIApplication sharedApplication].windows.firstObject endEditing:NO];

Могу поспорить, что вы имели в виду ДА вместо)
— Матросов Александр

2

Лучший способ отклонить клавиатуру из UITableView и UIScrollView:

tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag

2

В Swift 3 вы можете сделать следующее

UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)

1

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

 // dismiss keyboard (mostly macro)
[[UIApplication sharedApplication].delegate dismissKeyboard]; // call this in your to app dismiss the keybaord

// --- dismiss keyboard (in indexAppDelegate.h) (mostly macro)
- (void)dismissKeyboard;

// --- dismiss keyboard (in indexAppDelegate.m) (mostly macro)
// do this from anywhere to dismiss the keybard
- (void)dismissKeyboard {    // from: http://stackoverflow.com/questions/741185/easy-way-to-dismiss-keyboard

    UITextField *tempTextField = [[UITextField alloc] initWithFrame:CGRectZero];

    UIViewController *myRootViewController = <#viewController#>; // for simple apps (INPUT: viewController is whatever your root controller is called.  Probably is a way to determine this progragrammatically)
    UIViewController *uivc;
    if (myRootViewController.navigationController != nil) { // for when there is a nav stack
        uivc = myRootViewController.navigationController;
    } else {
        uivc = myRootViewController;
    }

    if (uivc.modalViewController != nil) { // for when there is something modal
        uivc = uivc.modalViewController;
    } 

    [uivc.view  addSubview:tempTextField];

    [tempTextField becomeFirstResponder];
    [tempTextField resignFirstResponder];
    [tempTextField removeFromSuperview];
    [tempTextField release];

}

Хм - почему отрицательный голос? Я обратил внимание на конкретные недостатки реального мира в другом ответе с проверенным кодом. Я могу понять отсутствие голосов "за", но голосование за меня на отрицательной территории - настоящее разочарование. Я все еще надеюсь, что приведенный выше ответ поможет кому-то еще.
— Джей Джей Рорер

1

Вам также может понадобиться переопределить UIViewController disablesAutomaticKeyboardDismissal, чтобы в некоторых случаях это работало. Это может быть сделано в UINavigationController, если он у вас есть.


1

Подкласс ваши текстовые поля ... а также текстовые представления

В подклассе положить этот код ..

-(void)conformsToKeyboardDismissNotification{

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissKeyBoard) name:KEYBOARD_DISMISS object:nil];
}

-(void)deConformsToKeyboardDismissNotification{

    [[NSNotificationCenter defaultCenter] removeObserver:self name:KEYBOARD_DISMISS object:nil];
}

- (void)dealloc{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [self resignFirstResponder];
}

В текстовом поле делегаты (аналогично для делегатов textview)

-(void)textFieldDidBeginEditing:(JCPTextField *)textField{
     [textField conformsToKeyboardDismissNotification];
}


- (void)textFieldDidEndEditing:(JCPTextField *)textField{
    [textField deConformsToKeyboardDismissNotification];
}

Все готово .. Теперь просто отправьте уведомление из любого места в вашем коде. Он подаст в отставку любую клавиатуру.


1

И в кратчайшие сроки мы можем сделать

UIApplication.sharedApplication().sendAction("resignFirstResponder", to: nil, from: nil, forEvent: nil)

Я не понимаю, как работает первый респондент .. где я могу поставить это? На мой взгляд, контроллер или делегат?
— Шаян С

Не имеет значения Вы можете положить его где угодно. т.е. действие кнопки
— Eike

1

Чтобы закрыть клавиатуру после ее появления, есть 2 случая :

  1. когда UITextField находится внутри UIScrollView

  2. когда UITextField находится вне UIScrollView

2. когда UITextField находится вне UIScrollView, переопределите метод в вашем подклассе UIViewController

Вы также должны добавить делегат для всех UITextView

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];
}
  1. При просмотре с прокруткой нажатие снаружи не вызовет события , поэтому в этом случае используйте Распознаватель жестов касания , перетащите UITapGesture для представления прокрутки и создайте для него IBAction .

чтобы создать IBAction, нажмите Ctrl + щелкните UITapGesture и перетащите его в .h файл viewcontroller.

Здесь я назвал tappedEvent в качестве имени моего действия

- (IBAction)tappedEvent:(id)sender {
      [self.view endEditing:YES];  }

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

http://samwize.com/2014/03/27/dismiss-keyboard-when-tap-outside-a-uitextfield-slash-uitextview/


0

Я ненавижу, что не существует "глобального" способа программно закрыть клавиатуру без использования вызовов частного API. Зачастую мне нужно программно отключать клавиатуру, не зная, какой объект является первым респондентом. Я прибег к проверкеself использования API времени выполнения Objective C, перечисляя все его свойства, вытаскивая те, которые имеют тип UITextField, и отправляя им resignFirstResponderсообщение.

Это не должно быть так сложно сделать ...


0

Это не красиво, но то, как я оставляю firstResponder, когда я не знаю, что это за ответчик:

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

  [self.invisibleField becomeFirstResponder];
  [self.invisibleField resignFirstResponder];

0

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

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

Я решил эту проблему гораздо более сложным, но гораздо более производительным способом, но с помощью синглтона / менеджера для механизма анимации моего приложения, и каждый раз, когда текстовое поле становилось отвечающим, я назначал его статическому элементу, который получал бы подметил (подал в отставку) на основе некоторых других событий ... это почти невозможно для меня объяснить в параграфе.

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


Решил это несколько месяцев назад;) В итоге я просто сохранил активное поле на фокусе и использовал его.
— Семьдесят

0

Немного более надежный метод, который мне нужно было использовать недавно:

- (void) dismissKeyboard {
    NSArray *windows = [UIApplication sharedApplication].windows;

    for(UIWindow *window in windows) [window endEditing:true];

    //  Or if you're only working with one UIWindow:

    [[UIApplication sharedApplication].keyWindow endEditing:true];
}

Я обнаружил, что некоторые другие «глобальные» методы не работают (например, UIWebView& WKWebViewотказался уйти в отставку).


0

Добавьте к вашему представлению A Recognizer Gesture Recognizer. И определите его ibaction

ваш .m файл будет похож

    - (IBAction)hideKeyboardGesture:(id)sender {
    NSArray *windows = [UIApplication sharedApplication].windows;
    for(UIWindow *window in windows) [window endEditing:true];
    [[UIApplication sharedApplication].keyWindow endEditing:true];
}

Это работает для меня


0

Да, endEditing - лучший вариант. А в iOW 7.0 UIScrollViewесть классная функция, позволяющая отключать клавиатуру при взаимодействии с видом прокрутки. Для достижения этого вы можете установить keyboardDismissModeсвойство UIScrollView.

Установите режим отклонения клавиатуры как:

tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag

У него есть несколько других типов. Посмотрите на этот яблочный документ .



0

самый простой способ - вызвать метод

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    if(![txtfld resignFirstResponder])
    {
        [txtfld resignFirstResponder];
    }
    else
    {

    }
    [super touchesBegan:touches withEvent:event];
}

Вам не нужно «если», resignFirstResponder все равно сделает это. Может быть, вы имели в виду - (BOOL) canResignFirstResponder?
— Семьдесят седьмого

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.