Простий спосіб відхилення клавіатури?


376

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


гарне доповнення до цього питання: stackoverflow.com/questions/1490573 / ...
ericsoco

Застереження до всіх наведених нижче відповідей. Якщо ви скажетеся після відставки КБ, КБ осиротить і не може бути звільнений. Ви повинні відхилити КБ у методі textFieldShouldReturn.
gjpc

26
глобальне звільнення з клавіатури правильним шляхом:[[[UIApplication sharedApplication] keyWindow] endEditing:YES];
Yerk

Я вважаю це відео корисним pinkstone.co.uk/… . Можливо, це може допомогти іншим.
enthusiasticgeek

Відповіді:


796

Спробуйте:

[self.view endEditing:YES];

1
Це, здається, працює (перевірено на ios4.1). Хоча він доступний лише на iOS 3.2 вгору. Я не впевнений, чи справді це гарантовано працює, або це просто не гарантований побічний ефект від виклику API таким чином, що це не підтверджено документально для роботи.
ЙосифH

3
Це прекрасно працювало для мене, і, безумовно, кращим є деякі інші відповіді на це питання. Документи кажуть, що він доступний в iOS 2.0 та новіших версіях.
антоун

8
Як зазначається в документації: "Цей метод розглядає поточний вигляд та його ієрархію підпогляду для текстового поля, яке наразі є першим відповіддю. Якщо він знайде його, він просить це текстове поле подати у відставку як перший відповідач. Якщо встановлено параметр сили ТАК, текстове поле ніколи навіть не запитується, воно змушене піти у відставку ". - тож це IMO правильна відповідь на початкове запитання (use-case: у мене форма з мільйонами полів, ну - десять ... чи так, і мені потрібно відхилити клавіатуру).
joshis

14
Відповідь не є помилковою, але трохи невірною, насправді так і має бути: [self.view endEditing:YES];оскільки значення BOOL ТАК / НІ в Objective-C.
chrisben

24
chrisben: Ви можете використовувати ТАК / НІ, ІСТИНА / ЛІЖ, 0/1.
Михайло Суперчинський

126

Ви можете змусити представлення, що редагується в даний час, відкликати свій статус першого відповіді [view endEditing:YES]. Це приховує клавіатуру.

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

(Ця відповідь раніше включала пару інших рішень, які також працювали, але були складнішими, ніж це потрібно. Я видалив їх, щоб уникнути плутанини.)


Але це лише заблокує компонент, щоб стати firstResponder, а не видалити поточний статус firstResponder з елемента.
Kendall Helmstetter Gelner

Що я мав на увазі підкреслюючи функцію стати FirstFesponder, щоб зберігати перший відповідь десь, щоб отримати доступ до нього (у цьому випадку подати у відставку) пізніше. Основна проблема полягає в тому, що Cocoa Touch не дає можливості запитати вікно або переглянути, який його перший відповідь.
Ніколас Райлі

+1 Додавання вирішених проблем, які я вирішував, стали вирішенням проблеми FirstFesponder, у мене виникали крани на інших полях UITextFields.
Джейсон Джордж

3
Це застаріло. [self.view endEditing:YES];Відповідь краще.
ftvs

1
Це не застаріло, ця відповідь пояснює, як саме [UIView endediting:]працює. В одному з розроблених нами додатків у UINavigationViewController було додано поле пошуку, якщо ви просто зателефонуєте [self.view endEditing:YES], як selfваш контролер перегляду, це не буде працювати, натомість я назвав цей метод безпосередньо з огляду області, де додано поле пошуку, наприклад: [self.mySearchBoxView endEditing:YES].
Ян Кассіо

92

Ви можете надіслати заявку з націленою на нульову дію, вона піде у відставку першого відповідача в будь-який час, не турбуючись про те, який перегляд має статус першого відповіді.

Завдання-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. У моїй програмі у мене є бічне меню панелі, і буває, що контролер перегляду «центру» показує клавіатуру. І я хочу відхилити клавіатуру, якщо буде показано меню бічної панелі. Тому я додав цей код у меню бокового рядка Клас 'метод viewWillAppear.
Jenn Eve

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];
    }

Приємне в цьому рішенні - це те, що воно фільтрує лише Taps, а не пальці. Тож якщо у вас є прокрутка вмісту над клавіатурою, пальці все одно прокручуватимуть і залишатимуть клавіатуру відображатися. Видаляючи розпізнавальник жестів після відсутності клавіатури, майбутні крани у вашому огляді нормально обробляються.


До свого @implementation я додав @property (призначити) UITapGestureRecognizer * tapRecognizer; і модифікований self.tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget: самодія: @selector (didTapAnywhere :)];
Професор Тодд

Я намагаюся зробити подібне, і я не отримую зворотного дзвінка. Цікаво: чому ваше майно "присвоєно"?
TahoeWolverine

Плюс один, і крім того, це має бути поведінка iOS за замовчуванням. Або хоча б додати простий спосіб перемикання кнопки відхилення.
Shaunti Fondrisi

24

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


врахуйте цей сценарій:

У мене є viewcontrollerдва текстових поля (ім’я користувача та пароль). і протокол viewcontrollerреалізаціїUITextFieldDelegate

Я роблю це в viewDidLoad

- (void)viewDidLoad 
{
    [super viewDidLoad];

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

і контролер перегляду реалізує необов'язковий метод як

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

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

У вашому випадку те ж саме буде працювати до тих пір, поки ви встановите весь делегат текстового поля для себе та реалізації textFieldShouldReturn


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

1
Бувають випадки, коли ви, можливо, захочете відхилити клавіатуру, не натискаючи кнопку "повернутись", наприклад, коли збирається відобразити меню бічної панелі
Пітер Джонсон

Відредаговано, щоб уточнити, що ця відповідь є актуальною лише у ситуаціях, коли натискання "повернення" є прийнятним рішенням. [У моєму випадку я також хотів відхилити клавіатуру, коли користувач торкається поза полем, що редагується; ця відповідь у цьому не допомагає.]
ToolmakerSteve

14

Кращий підхід - мати щось "вкрасти" статус першої відповіді.

Оскільки UIApplication є підкласом UIResponder, ви можете спробувати:

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

Якщо цього не зробити, створіть нове UITextField з нульовим розміром кадру, додайте його до подання десь і зробіть щось подібне (за ним слід подати у відставку).


1
Трюк UIApplication не працює (він виходить з ладу, принаймні, на тренажері), але вам не потрібен UITextField нульового розміру - просто виберіть будь-яке випадкове поле і зробіть це з ним. NSResponder перетворився на FFRResponder - це лише метод сповіщення, але UIResponder - ні (дизайн гірший).
Ніколас Райлі

1
Ага, дякую! Він виходить з ладу, називаючи його на UIApplication, але нульовий розмір UITextField працює чудово, і мені не потрібно отримувати жодне з моїх попередніх полів.
Сімдесяти

Навіщо хтось це робити, якщо для цього існує офіційний, ідеально хороший і документально підтверджений метод?
Maciej Swic

2
Вони не побачать відповіді, яка найбільше схвалює, для кращого рішення. Тоді воно було мало відоме (моя відповідь була з 2009 року, інша відповідь надійшла через рік пізніше, у 2010 році). але я залишаю це для нащадків.
Kendall Helmstetter Gelner

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, просто зателефонуйте [переглянути endEditing: YES]. Це робить те саме.
n13,

Ага! Остаточне рішення! Я перепробував багато способів, тільки цей працює для мене! Дуже дякую!
douyw

6

@Nicholas Riley & @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];
}

EDIT

Поправка до моєї відповіді включена 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

Ось що я використовую в своєму коді. Це працює як шарм!

Додайте у свій переглядcontroller.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;
}

... Потім прив’яжіть вашTextBox до фактичного текстового поля

- (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

У швидкому 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];

}

Хм - чому голосування проти? Я вирішив конкретні недоліки в іншій відповіді з перевіреним кодом. Я можу зрозуміти нестачу голосів, але голосування мене на негативній території - це справжнє розчарування. Я все ще сподіваюсь, що наведена відповідь допомагає комусь іншому.
JJ Rohrer

1

Можливо, вам також знадобиться скасувати UIViewController onesposobleAutomaticKeyboardDismissal, щоб у деяких випадках це діяло. Це можливо доведеться зробити на 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];
}

У текстовому полі делегати (аналогічно для представників перегляду тексту)

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


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

Все встановлено. Тепер просто опублікуйте сповіщення з будь-якої точки вашого коду. Він подасть у відставку будь-яку клавіатуру.


1

І швидко ми можемо зробити

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

Я не розумію, як працює перший відгук .. куди я це покладу? на мій погляд контролер або делегат?
Шаян C

Не має значення. Ви можете помістити його куди завгодно. тобто дія кнопки
Ейке

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

Це не дуже, але те, як я подаю у відставку першого респондента, коли я не знаю, що це за відповідь:

Створіть поле 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

Додайте до свого перегляду розпізнавальник жестів і натисніть на нього

ваш файл .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.