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


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.