iOS - Отключить клавиатуру при касании за пределами UITextField


461

Мне интересно, как заставить клавиатуру исчезать, когда пользователь касается вне UITextField.


8
У Дмитрия был правильный ответ. Это не проблема жеста, это проблема отставки первого респондента. Ответ Dmirty также является решением, рекомендованным Марком, Наттингом и ЛеМаршем в « Начале разработки под iOS 4» , глава 4, стр. 83.
13

Ответы:


760

Вам нужно будет добавить UITapGestureRecogniserи назначить его представлению, а затем вызвать отставку первым респондентом наUITextField на его селектора.

Код:

В viewDidLoad

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];

[self.view addGestureRecognizer:tap];

В dismissKeyboard:

-(void)dismissKeyboard 
{
    [aTextField resignFirstResponder];
}

(Где aTextFieldтекстовое поле, которое отвечает за клавиатуру)

Версия Swift 3 выглядит так

let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard (_:)))
self.view.addGestureRecognizer(tapGesture)

Для dismissKeyboard

@objc func dismissKeyboard (_ sender: UITapGestureRecognizer) {
    aTextField.resignFirstResponder()
}

6
Это работает, но также отключает или делает кнопки панели навигации неактивными. Так есть ли обходной путь для этого?
Парт Бхатт

137
Я думаю, что лучше, чем [aTextField resignFirstResponder]было бы, [self.view endEditing:YES];это не нуждается в ссылке на текстовое поле и будет работать для нескольких текстовых полей
Джулиан Крол

90
Таким образом, без определения каких-либо методов, однострочник будет:[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self.view action:@selector(endEditing:)]];
Subhas

8
@ParthBhatt Я добавил [tap setCancelsTouchesInView:NO];за ответ @qiaoyi; У меня была проблема с таблицей, не отвечающей на выбор строки. 5 лет спустя, надеюсь, это поможет кому-то еще.
Том Ховард

7
Swift one-liner: self.view.addGestureRecognizer(UITapGestureRecognizer(target: self.view, action: #selector(UIView.endEditing(_:))))
неисправность

176

Я растянул несколько ответов.

Используйте ивар, который инициализируется во время viewDidLoad:

UIGestureRecognizer *tapper;

- (void)viewDidLoad
{
    [super viewDidLoad];
    tapper = [[UITapGestureRecognizer alloc]
                initWithTarget:self action:@selector(handleSingleTap:)];
    tapper.cancelsTouchesInView = NO;
    [self.view addGestureRecognizer:tapper];
}

Уволить то, что когда-либо в настоящее время редактирует:

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

Фантастика, это работает на UITableView! это спасет мой день! В качестве примечания я буду использовать [UITextField resignFirstResponder] вместо [UIView endEditing:], потому что у меня больше UITextField, а endEditing дает неправильную позицию прокрутки, даже если новый UITextField виден.
Доктор Луиджи

1
Совершенно неправильно, потому что UITapGestureRecognizer никогда не добавляется в представление!

1
Какова цель отмены TouchInView здесь?
Адам Джонс

3
Если вы не добавите сюда cancellsTouchesInView = false, вы не сможете выбирать другие типы элементов в своем представлении. Ваши касания будут перехвачены жестом распознавателя.
HalR

104

Проверьте это, это будет самый простой способ сделать это,

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
      [self.view endEditing:YES];// this will do the trick
}

Или

Эта библиотека будет обрабатывать, включая автоматическую прокрутку полосы прокрутки, нажатие клавиши пробела, чтобы скрыть клавиатуру и т. Д.

https://github.com/michaeltyson/TPKeyboardAvoiding


@ Рамеш да, это так, но не так. вам нужно создать подкласс из UITableView и внутри этого класса реализовать метод touchesBegan, а затем вызвать метод endEditing. оно работает! не забудьте установить класс для вашей таблицы в только что созданном классе.
Прасад Де Зойса,

3
Он не скрывает клавиатуру, когда пользователь касается других элементов управления в представлении. Пример: у меня есть UIButton и UITextField на UIView. Я нажимаю на UITextField, затем нажимаю на кнопку, клавиатура в этом случае не скрывается.
Джейкоб Дэм

2
@JacobDam Ты прав. Цель состоит в том, чтобы повторно подписаться первым респондентом, чтобы скрыть клавиатуру, если что-то происходит за пределами aTextField.

88

Я вижу, что у некоторых людей возникают проблемы с использованием UITapGestureRecognizerметода. Самый простой способ, которым я выполнил эту функцию, при этом оставляя неизменным поведение нажатия моей существующей кнопки, это добавление только одной строки к ответу @ Jensen2k:

[tap setCancelsTouchesInView:NO];

Это позволило моим существующим кнопкам по-прежнему работать без использования метода @Dmitry Sitnikov.

Прочитайте об этом propertyздесь (поиск CancelsTouchesInView): Ссылка на класс UIGestureRecognizer

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


3
Я также хотел бы добавить, для тех, кто использует фоновое изображение в задней части вида UIImageView, добавьте, [imageView setUserInteractionEnabled:NO];и вы «щелкнете» по нему, чтобы этот метод работал.
Пол Пилен

55

Лучше сделать ваш UIViewэкземпляр UIControl(в конструкторе интерфейсов) и затем связать их TouchUpInsideсобытие с dismissKeyboardметодом. Этот IBActionметод будет выглядеть так:

- (IBAction)dismissKeyboard:(id)sender {
    [aTextBox resignFirstResponder];
}

1
Спасибо! Это сработало для меня, а другие решения нет. ( UITapGestureRecognizerмешало постукивать по кнопкам внутри вида). touchesEndedне сработало, потому что произошла UIScrollViewпутаница с цепочкой респондента.)
jlstrecker

1
Это прекрасно работает, но должно быть добавлено ко всему, что вы хотите, чтобы отклонить клавиатуру. Есть ли способ автоматически отправить текстовое поле в отставку первого респондента, нажав на что-нибудь еще?
Исаак Оверекер

4
Вам не нужно делать UIView UIControl. Убедитесь, что в UIView включено взаимодействие с пользователем.
Sofi Software LLC

1
@SofiSoftwareLLC Ваше предложение не работает для меня. Я должен был сделать его UIControl, даже когда была включена проверка взаимодействия с пользователем.
три чашки

1
Используя StoryBoard, я изменил UIView на UIControl (где я бы выбрал подкласс UIView, если бы я его создал). Это работает хорошо. Я не сталкивался с какими-либо проблемами. iOS8.
ToddB

30

Swift 4

Настройте UIViewControllerэтот метод расширения один раз, например viewDidLoad:

override func viewDidLoad() {
    super.viewDidLoad()
    self.setupHideKeyboardOnTap()
}

и клавиатура будет закрыта даже при нажатии на NavigationBar.

import UIKit
extension UIViewController {
    /// Call this once to dismiss open keyboards by tapping anywhere in the view controller
    func setupHideKeyboardOnTap() {
        self.view.addGestureRecognizer(self.endEditingRecognizer())
        self.navigationController?.navigationBar.addGestureRecognizer(self.endEditingRecognizer())
    }

    /// Dismisses the keyboard from self.view
    private func endEditingRecognizer() -> UIGestureRecognizer {
        let tap = UITapGestureRecognizer(target: self.view, action: #selector(self.view.endEditing(_:)))
        tap.cancelsTouchesInView = false
        return tap
    }
}

2
Братан, ты прибил это !! Этот ответ идеально подходит и отлично работает, большое спасибо.
ржавчина

28

Версия Swift, это работает в сочетании с другими элементами (вроде того UIButtonили другого UITextField):

override func viewDidLoad() {
    super.viewDidLoad()

    let tapper = UITapGestureRecognizer(target: self, action:#selector(endEditing))
    tapper.cancelsTouchesInView = false
    view.addGestureRecognizer(tapper)
}

1
цель должна быть, selfа неself.view
EI Captain v2.0

1
цель должна быть self.view. В противном случае приведенный выше код вылетит.
Нага Маллеш Маддали

canclesTouchesInViewэто удобное свойство для использования. Спасибо.
JonSlowCN

Старые привычки умирают с трудом. Что эта точка с запятой делает здесь? ;)
Александр Григорьевич

@AlexandreG. Действительно, тем более что я вообще кодирую c#. К сведению, что точка с запятой разрешена по синтаксису, просто нет необходимости.
Роб

17

Как насчет этого: я знаю, что это старый пост. Это может помочь кому-то :)

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {  
    NSArray *subviews = [self.view subviews];
    for (id objects in subviews) {
        if ([objects isKindOfClass:[UITextField class]]) {
            UITextField *theTextField = objects;
            if ([objects isFirstResponder]) {
                [theTextField resignFirstResponder];
            }
        } 
    }
}

Я не проверял UITextField, поэтому он работает для любого типа ввода. Не вижу никаких проблем.
Франк

15

Это хорошее общее решение:

Objective-C:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];    
}

Swift:

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
    self.view.endEditing(true)
}

Основано на решении @icodebuster: https://stackoverflow.com/a/18756253/417652



10

Я думаю, что самый простой (и лучший) способ сделать это - создать подкласс вашего глобального представления и использовать hitTest:withEventметод для прослушивания любого прикосновения. Касания на клавиатуре не зарегистрированы, поэтому hitTest: withEvent вызывается только когда вы касаетесь / прокручиваете / проводите / зажимаете ... где-то еще, а затем вызываете [self endEditing:YES].

Это лучше, чем использовать, touchesBeganпотому что touchesBeganне вызывается, если вы нажмете кнопку в верхней части представления. Это лучше, чем тот, UITapGestureRecognizerкоторый не может распознать, например, жест прокрутки. Это также лучше, чем использование тусклого экрана, потому что в сложном и динамичном пользовательском интерфейсе нельзя ставить тусклый экран везде. Более того, он не блокирует другие действия, вам не нужно дважды нажимать, чтобы выбрать кнопку снаружи (как в случаеUIPopover ).

Кроме того, это лучше, чем звонить [textField resignFirstResponder], потому что у вас может быть много текстовых полей на экране, так что это работает для всех них.


К сожалению, это, кажется, мешает UISearchBar 'X' для очистки текста.
Хагги

1
Есть некоторые проблемы с этим подходом. Например, вы не можете прокручивать прокрутку без потери фокуса на текстовом поле. не рекомендуется для более сложных сценариев ... лично я предпочитаю uicontrol-версию от Дмитрия, возможно, дополненную комментарием от Sofi Software.
Каценхут

Одним из примеров прокрутки является приложение электронной почты, когда вы набираете текст в строке поиска, а затем прокручиваете список почты, клавиатура отклоняется.
Энцо Тран

Это лучший подход, который я сделал для других моих проектов.
Чандрамани


6

Если представление вообще встроено в UIScrollView то вы можете использовать следующее:

tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;

Первый из них будет анимировать экранную клавиатуру при прокрутке таблицы, а второй - скрыть клавиатуру, как приложение «Стандартные сообщения».

Обратите внимание, что они доступны на iOS 7.0 или выше.


6

Вы можете сделать это, используя раскадровку в XCode 6 и выше:


Создать действие, чтобы скрыть клавиатуру

Добавьте это в файл заголовка класса, используемого вашим ViewController:

@interface TimeDelayViewController : UIViewController <UITextFieldDelegate>

- (IBAction)dissmissKeyboardOnTap:(id)sender;

@end

Затем добавьте это в файл реализации того же ViewController:

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

Теперь это будет одно из «полученных действий» для вашей раскадровки (например, ViewController):

введите описание изображения здесь


Подключите действие к пользовательскому событию

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

Важно. Вам необходимо преобразовать UIView, который содержится в вашей раскадровке, в UIControl , чтобы он мог принимать события. Выберите представление в иерархии сцены View Controller:

введите описание изображения здесь

... и измените его класс:

введите описание изображения здесь

Теперь перетащите курсор из маленького кружка рядом с «полученным действием» для вашей сцены на «пустую» часть вашей сцены (фактически вы перетаскиваете «Полученное действие» в UIControl). Вам будет показан выбор событий, к которым вы можете подключить свое действие:

введите описание изображения здесь

Выберите опцию «подправить изнутри». Теперь вы подключили созданный IBAction к пользовательскому действию касания клавиатуры. Когда пользователь нажимает на клавиатуру, она будет скрыта.

(ПРИМЕЧАНИЕ. Чтобы привязать действие к событию, вы также можете перетащить полученное действие непосредственно в UIControl в иерархии View Controllers. В иерархии оно отображается как «Control».)


Спасибо за решение и подробное объяснение. Действительно полезно для меня.
Юнсян Руан

5

Если я вас правильно понял, вы хотите уйти в отставку, нажав на кнопку вне, textfieldно у вас нет ссылки на вашtextfield .

Попробуй это;

  • Возьмите глобальный textField, давайте назовем его reftextField
  • Теперь в textFieldDidBeginEditingуказанном текстовом поле

    - (void) textFieldDidBeginEditing:(UITextField *)textField{
        reftextField = textField;
    }
  • Теперь вы можете с радостью использовать на любой кнопке часы (рекомендуется добавить прозрачную кнопку при начале редактирования)

    - (void)dismissKeyboard {
          [reftextField resignFirstResponder];
    }
  • Или для отставки готовой кнопки попробуйте это.

    //for resigning on done button    
    - (BOOL) textFieldShouldReturn:(UITextField *)textField{
        [textField resignFirstResponder];
        return YES;
    }

3

Просто чтобы добавить сюда список моей версии о том, как отклонить клавиатуру при внешнем прикосновении.

viewDidLoad:

UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
[self.view addGestureRecognizer:singleTap];

Где угодно:

-(void)handleSingleTap:(UITapGestureRecognizer *)sender{
    [textFieldName resignFirstResponder];
    puts("Dismissed the keyboard");
}

3

Здесь вы найдете множество отличных ответов об использовании кнопки UITapGestureRecognizer--all of break UITextField(X). Решение состоит в том, чтобы подавить распознаватель жестов через его делегат:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    BOOL touchViewIsButton = [touch.view isKindOfClass:[UIButton class]];
    BOOL touchSuperviewIsTextField = [[touch.view superview] isKindOfClass:[UITextField class]];
    return !(touchViewIsButton && touchSuperviewIsTextField);
}

Это не самое надежное решение, но оно работает для меня.


Точно, все вышеперечисленное не работает, если я нажимаю в том же текстовом поле. Он подает в отставку, даже текстовое поле мой ответчик. и он также закрывает клавиатуру при нажатии кнопки очистки внутри textField
Mrug

Я бы упростить его просто делать тест на кнопку: return !touchViewIsButton. Я предполагаю, что любые другие кнопки, которые должны отклонить клавиатуру, должны делать это в своих действиях. Кроме того, TouchUpInside может не вызываться при изменении раскладки при отклонении клавиатуры.
Мариан Черны

3

Вы можете создать категорию для UiView и переопределить метод touchesBegan следующим образом.

Это работает нормально для меня. И это централизованное решение этой проблемы.

#import "UIView+Keyboard.h"
@implementation UIView(Keyboard)

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.window endEditing:true];
    [super touchesBegan:touches withEvent:event];
}
@end

3

Быстрая версия ответа @ Jensen2k:

let gestureRecognizer : UITapGestureRecognizer = UITapGestureRecognizer.init(target: self, action: "dismissKeyboard")
self.view.addGestureRecognizer(gestureRecognizer)

func dismissKeyboard() {
    aTextField.resignFirstResponder()
}

Один лайнер

self.view.addTapGesture(UITapGestureRecognizer.init(target: self, action: "endEditing:"))

2

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

Итак, я добавил в пример Барри следующее:

- (void) textFieldDidBeginEditing:(UITextField *)textField
{
    _textBeingEdited = textField;
}
-(void) textFieldDidEndEditing:(UITextField *)textField
{
    _textBeingEdited = nil;
}

Также я изменил метод hideKeyboard следующим образом:

- (IBAction)hideKeyboard:(id)sender
{
    // Just call resignFirstResponder on all UITextFields and UITextViews in this VC
    // Why? Because it works and checking which one was last active gets messy.
    //UITextField * tf = (UITextField *) sender;
    [_textBeingEdited resignFirstResponder];
}

2

Один из самых простых и коротких способов - добавить этот код в свой viewDidLoad

[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc]
                                     initWithTarget:self.view
                                     action:@selector(endEditing:)]];

2
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

    if let touch = touches.first{
     view.endEditing(true)

     }
}

2

Я попробовал многие ответы здесь, и мне не повезло. Мой распознаватель жестов касания всегда заставлял меня UIButtonsне отвечать при касании, даже когда я установилcancelsTouchesInView свойство распознавателя жестов на НЕТ.

Вот что в итоге решило проблему:

Ивару:

UITapGestureRecognizer *_keyboardDismissGestureRecognizer;

Когда текстовое поле начинает редактирование, установите распознаватель жестов:

- (void) textFieldDidBeginEditing:(UITextField *)textField
{
    if(_keyboardDismissGestureRecognizer == nil)
    {
        _keyboardDismissGestureRecognizer = [[[UITapGestureRecognizer alloc]
                                       initWithTarget:self
                                       action:@selector(dismissKeyboard)] autorelease];
        _keyboardDismissGestureRecognizer.cancelsTouchesInView = NO;

        [self.view addGestureRecognizer:_keyboardDismissGestureRecognizer];
    }
}

Тогда дело в том, как настроить dismissKeyboardметод:

- (void) dismissKeyboard
{
    [self performSelector:@selector(dismissKeyboardSelector) withObject:nil afterDelay:0.01];
}

- (void) dismissKeyboardSelector
{
    [self.view endEditing:YES];

    [self.view removeGestureRecognizer:_keyboardDismissGestureRecognizer];
    _keyboardDismissGestureRecognizer = nil;
}

Я полагаю, что есть что-то о том, как вывести dismissKeyboardSelectorвыполнение из стека выполнения обработки касанием ...



1

Это работает

В этом примере aTextField является единственным UITextField .... Если есть другие или UITextViews, есть еще кое-что сделать.

// YourViewController.h
// ...
@interface YourViewController : UIViewController /* some subclass of UIViewController */ <UITextFieldDelegate> // <-- add this protocol
// ...
@end

// YourViewController.m

@interface YourViewController ()
@property (nonatomic, strong, readonly) UITapGestureRecognizer *singleTapRecognizer;
@end
// ...

@implementation
@synthesize singleTapRecognizer = _singleTapRecognizer;
// ...

- (void)viewDidLoad
{
    [super viewDidLoad];
    // your other init code here
    [self.view addGestureRecognizer:self.singleTapRecognizer];

{

- (UITapGestureRecognizer *)singleTapRecognizer
{
    if (nil == _singleTapRecognizer) {
        _singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapToDismissKeyboard:)];
        _singleTapRecognizer.cancelsTouchesInView = NO; // absolutely required, otherwise "tap" eats events.
    }
    return _singleTapRecognizer;
}

// Something inside this VC's view was tapped (except the navbar/toolbar)
- (void)singleTapToDismissKeyboard:(UITapGestureRecognizer *)sender
{
    NSLog(@"singleTap");
    [self hideKeyboard:sender];
}

// When the "Return" key is pressed on the on-screen keyboard, hide the keyboard.
// for protocol UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField*)textField
{
    NSLog(@"Return pressed");
    [self hideKeyboard:textField];
    return YES;
}

- (IBAction)hideKeyboard:(id)sender
{
    // Just call resignFirstResponder on all UITextFields and UITextViews in this VC
    // Why? Because it works and checking which one was last active gets messy.
    [aTextField resignFirstResponder];
    NSLog(@"keyboard hidden");
}

1
- (void)viewDidLoad
{
    [super viewDidLoad]; 

UITapGestureRecognizer *singleTapGestureRecognizer = [[UITapGestureRecognizer alloc]
                                                          initWithTarget:self
                                                          action:@selector(handleSingleTap:)];
    [singleTapGestureRecognizer setNumberOfTapsRequired:1];
    [singleTapGestureRecognizer requireGestureRecognizerToFail:singleTapGestureRecognizer];

    [self.view addGestureRecognizer:singleTapGestureRecognizer];
}

- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer
{
    [self.view endEditing:YES];
    [textField resignFirstResponder];
    [scrollView setContentOffset:CGPointMake(0, -40) animated:YES];

}

1

Добавьте этот код в ваш файл ViewController.m :

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.view endEditing:YES];
}

1

В этом случае можно использовать ScrollView и добавить его TextFieldв ScrollView, и я хочу нажать ScrollViewи просмотреть, а затем закрыть клавиатуру. Я попытался создать пример кода на всякий случай. Нравится,

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var scrollView: UIScrollView!
    @IBOutlet weak var textField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.tap(_:)))
        view.addGestureRecognizer(tapGesture)
        // Do any additional setup after loading the view, typically from a nib.
    }
    func tap(gesture: UITapGestureRecognizer) {
        textField.resignFirstResponder()
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

Ваш Раскадровка Посмотрите на это как.

введите описание изображения здесь


1

Вы можете использовать метод UITapGestureRecongnizer для отклонения клавиатуры, щелкнув за пределами UITextField. При использовании этого метода всякий раз, когда пользователь нажимает за пределами UITextField, клавиатура получает отклонение. Ниже приведен фрагмент кода для его использования.

 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
                                   initWithTarget:self
                                   action:@selector(dismissk)];

    [self.view addGestureRecognizer:tap];


//Method
- (void) dismissk
{
    [abctextfield resignFirstResponder];
    [deftextfield resignFirstResponder];

}

1
  • Установить текстовые поля делегата в представлении загрузил:

    override func viewDidLoad() 
    {
      super.viewDidLoad()
      self.userText.delegate = self
    }
  • Добавьте эту функцию:

    func textFieldShouldReturn(userText: UITextField!) -> Bool 
    {
     userText.resignFirstResponder()
     return true;
    }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.