Как программно проверить, присутствует ли клавиатура в приложении для iOS?

Мне нужно проверить состояние видимости клавиатуры в моем приложении для iOS.

псевдокод:

if(keyboardIsPresentOnWindow) {
    //Do action 1
}
else if (keyboardIsNotPresentOnWindow) {
    //Do action 2
}

Как я могу проверить это состояние?

Ответ 1

... или выполните простой путь:

При вводе текстового поля он становится первым ответчиком и появляется клавиатура. Вы можете проверить состояние клавиатуры с помощью [myTextField isFirstResponder]. Если он возвращает YES, тогда клавиатура активна.

Ответ 2

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

@interface KeyboardStateListener : NSObject {
    BOOL _isVisible;
}
+ (KeyboardStateListener *)sharedInstance;
@property (nonatomic, readonly, getter=isVisible) BOOL visible;
@end

static KeyboardStateListener *sharedInstance;

@implementation KeyboardStateListener

+ (KeyboardStateListener *)sharedInstance
{
    return sharedInstance;
}

+ (void)load
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    sharedInstance = [[self alloc] init];
    [pool release];
}

- (BOOL)isVisible
{
    return _isVisible;
}

- (void)didShow
{
    _isVisible = YES;
}

- (void)didHide
{
    _isVisible = NO;
}

- (id)init
{
    if ((self = [super init])) {
        NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
        [center addObserver:self selector:@selector(didShow) name:UIKeyboardDidShowNotification object:nil];
        [center addObserver:self selector:@selector(didHide) name:UIKeyboardWillHideNotification object:nil];
    }
    return self;
}

@end

Ответ 3

Создайте UIKeyboardListener, если вы знаете, что клавиатура не видна, например, вызывая [UIKeyboardListener shared] из applicationDidFinishLaunching.

@implementation UIKeyboardListener

+ (UIKeyboardListener) shared {
    static UIKeyboardListener sListener;    
    if ( nil == sListener ) sListener = [[UIKeyboardListener alloc] init];

    return sListener;
}

-(id) init {
    self = [super init];

    if ( self ) {
        NSNotificationCenter        *center = [NSNotificationCenter defaultCenter];
        [center addObserver:self selector:@selector(noticeShowKeyboard:) name:UIKeyboardDidShowNotification object:nil];
        [center addObserver:self selector:@selector(noticeHideKeyboard:) name:UIKeyboardWillHideNotification object:nil];
    }

    return self;
}

-(void) noticeShowKeyboard:(NSNotification *)inNotification {
    _visible = true;
}

-(void) noticeHideKeyboard:(NSNotification *)inNotification {
    _visible = false;
}

-(BOOL) isVisible {
    return _visible;
}

@end

Ответ 4

Я думаю, вам нужно использовать уведомления, которые предоставляются о клавиатуре:

От: http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UITextField_Class/Reference/UITextField.html

Уведомления о клавиатуре

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

* UIKeyboardWillShowNotification
* UIKeyboardDidShowNotification
* UIKeyboardWillHideNotification
* UIKeyboardDidHideNotification

Для получения дополнительной информации об этих уведомления, см. их описания в Справочнике классов UIWindow. Для информация о том, как показывать и скрывать на клавиатуре, см. раздел "Текст и Интернет".

Ответ 5

Использование иерархии subview окна как индикатора для показа клавиатуры - это взломать. Если Apple сменит их базовую реализацию, все эти ответы нарушатся.

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

В AppDelegate.h:

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (assign, nonatomic) BOOL keyboardIsShowing;

@end

В AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

    // Monitor keyboard status application wide
    self.keyboardIsShowing = NO;
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:)
                                             name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:)
                                             name:UIKeyboardWillHideNotification object:nil];

    return YES;
}

- (void)keyboardWillShow:(NSNotification*)aNotification
{
    self.keyboardIsShowing = YES;
}

- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    self.keyboardIsShowing = NO;
}

Затем вы можете проверить, используя:

BOOL keyboardIsShowing = ((AppDelegate*)[UIApplication sharedApplication].delegate).keyboardIsShowing;

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

Ответ 6

Внедрение Swift 3

    import Foundation
class KeyboardStateListener: NSObject
{
    static let shared = KeyboardStateListener()
    var isVisible = false

    func start() {
        NotificationCenter.default.addObserver(self, selector: #selector(didShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(didHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }

    func didShow()
    {
        isVisible = true
    }

    func didHide()
    {
        isVisible = false
    } 
}

Ответ 7

Теперь в iOS8 это решение, конечно, не работает. Первоначально он был написан для IOS4/5.

Попробуйте это решение:

- (BOOL) isKeyboardOnScreen 
{
    BOOL isKeyboardShown = NO;

    NSArray *windows = [UIApplication sharedApplication].windows;
    if (windows.count > 1) {
        NSArray *wSubviews =  [windows[1]  subviews];
        if (wSubviews.count) {
            CGRect keyboardFrame = [wSubviews[0] frame];
            CGRect screenFrame = [windows[1] frame];
            if (keyboardFrame.origin.y+keyboardFrame.size.height == screenFrame.size.height) {
                isKeyboardShown = YES;
            }
        }
    }

    return isKeyboardShown;
}

Ответ 8

Это из руководства по программированию текста iOS, опубликованного Apple здесь: https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html

В основном вызывать "registerForKeyBoardNotifications" в вашем ViewDidLoad. Затем каждый раз, когда клавиатура становится активной, вызывается "keyboardWasShown". И каждый раз, когда клавиатура исчезает, вызывается "keyboardWillBeHidden".

// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:) name:UIKeyboardWillHideNotification object:nil];
}

// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification {
    NSLog(@"Keyboard is active.");
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
    scrollView.contentInset = contentInsets;
    scrollView.scrollIndicatorInsets = contentInsets;

    // If active text field is hidden by keyboard, scroll it so it visible
    // Your app might not need or want this behavior.
    CGRect aRect = self.view.frame;
    aRect.size.height -= kbSize.height;
    if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) {
        [self.scrollView scrollRectToVisible:activeField.frame animated:YES];
    }
}

// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification {
    NSLog(@"Keyboard is hidden");
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    scrollView.contentInset = contentInsets;
    scrollView.scrollIndicatorInsets = contentInsets;
}

Ответ 9

Несколько наблюдений:

Рекомендуемый шаблон для одноэлементного объекта будет следующим. dispatch_once гарантирует, что класс инициализируется один раз поточно-безопасным способом, а статическая переменная не видна снаружи. И это стандартный GCD, поэтому не нужно знать о деталях низкого уровня Objective-C.

+ (KeyboardStateListener *)sharedInstance
{
    static KeyboardStateListener* shared;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        shared = [[KeyboardStateListener alloc] init];
        // Other initialisations
    });

    return shared;
}

Обычно вы не хотите знать, является ли клавиатура видимой или нет, но насколько она велика. Клавиатуры не все имеют одинаковый размер. Клавиатуры iPhone меньше клавиатур iPad. Поэтому вам нужно другое свойство @property (readonly, nonatomic) CGRect keyboardRect;, которое установлено в методе noticeShowKeyboard: следующим образом:

NSValue* value = notification.userInfo [UIKeyboardFrameEndUserInfoKey];
_keyboardRect = value.CGRectValue;

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

KeyboardStateListener* listener = [KeyboardStateListener sharedInstance];
CGRect windowRect = listener.keyboardRect;
CGRect viewRect = [myView convertRect:windowRect fromView:self.window];

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

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

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

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

Ответ 10

И вот как это сделать в Swift:

 func registerForKeyboardNotifications() {
    NSNotificationCenter.defaultCenter().addObserver(
        self,
        selector: "keyboardWasShown:",
        name: UIKeyboardDidShowNotification,
        object: nil)

    NSNotificationCenter.defaultCenter().addObserver(
        self,
        selector: "keyboardWillBeHidden:",
        name: UIKeyboardWillHideNotification,
        object: nil)
}

func keyboardWasShown(notification: NSNotification) {
    println("Keyboard was shown");
}

func keyboardWillBeHidden(notification: NSNotification) {
    println("Keyboard was dismissed");
}

Не забудьте отменить регистрацию:

 override func viewWillDisappear(animated: Bool) {
    NSNotificationCenter.defaultCenter().removeObserver(self,
        name: UIKeyboardDidShowNotification,
        object: nil)

    NSNotificationCenter.defaultCenter().removeObserver(self,
        name: UIKeyboardWillHideNotification,
        object: nil)
}

И если вы хотите отключить клавиатуру при нажатии кнопки "Возврат":

class ViewController: UIViewController, UITextFieldDelegate {

@IBOutlet weak var yourTextField: UITextField!

override func viewDidLoad() {
    super.viewDidLoad()
    registerForKeyboardNotifications()
    yourTextField.delegate = self
}

func textFieldShouldReturn(textField: UITextField!) -> Bool {
    self.view.endEditing(true);
    return false;
}

}

Ответ 11

Быстрая реализация:

class KeyboardStateListener: NSObject
{
  static var shared = KeyboardStateListener()
  var isVisible = false

  func start() {
    let nc = NSNotificationCenter.defaultCenter()
    nc.addObserver(self, selector: #selector(didShow), name: UIKeyboardDidShowNotification, object: nil)
    nc.addObserver(self, selector: #selector(didHide), name: UIKeyboardDidHideNotification, object: nil)
  }

  func didShow()
  {
    isVisible = true
  }

  func didHide()
  {
    isVisible = false
  } 
}

Поскольку swift не запускает метод класса load при запуске, важно запустить эту службу при запуске приложения:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool
{
  ...    
  KeyboardStateListener.shared.start() 
}

Ответ 12

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

+(BOOL)isKeyboardVisible{
    static id tokenKeyboardWillShow = nil;
    static id tokenKeyboardWillHide = nil;
    static BOOL isKbVisible = NO;
    @synchronized (self) {
        if (tokenKeyboardWillShow == nil){
            tokenKeyboardWillShow = [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillShowNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
                @synchronized (self) {
                    isKbVisible = YES;
                }
            }];
        }

        if (tokenKeyboardWillHide == nil){
            tokenKeyboardWillHide = [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillHideNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
                @synchronized (self) {
                    isKbVisible = NO;
                }
            }];
        }
    }

    return isKbVisible;
}

Ответ 13

Добавить расширение

extension UIApplication {   
/// Checks if view hierarchy of application contains 'UIRemoteKeyboardWindow' if it does, keyboard is presented
var isKeyboardPresented: Bool {
    if let keyboardWindowClass = NSClassFromString("UIRemoteKeyboardWindow"), self.windows.contains(where: { $0.isKind(of: keyboardWindowClass) }) {
        return true
    } else {
        return false
    }
}

}

Затем проверьте, если клавиатура присутствует,

if UIApplication.shared.isKeyboardPresented {
     print("Keyboard presented")
} else { 
     print("Keyboard is not presented")
}

Ответ 14

Попробуйте эту функцию

BOOL UIKeyboardIsVisible(){

BOOL keyboardVisible=NO;
// Locate non-UIWindow.
UIWindow *keyboardWindow = nil;
for (UIWindow *testWindow in [[UIApplication sharedApplication] windows]) {
    if (![[testWindow class] isEqual:[UIWindow class]]) {
        keyboardWindow = testWindow;
        break;
    }
}
// Locate UIKeyboard.
for (UIView *possibleKeyboard in [keyboardWindow subviews]) {
    // iOS 4 sticks the UIKeyboard inside a UIPeripheralHostView.
    if ([[possibleKeyboard description] hasPrefix:@"<UIPeripheralHostView"]) {
        keyboardVisible=YES;
    }
    if ([[possibleKeyboard description] hasPrefix:@"<UIKeyboard"]) {
        keyboardVisible=YES;
        break;
    }
}
return keyboardVisible;

}

from: iOS: Как получить доступ к` UIKeyboard`?

Ответ 15

BOOL isTxtOpen = [txtfieldObjct isFirstReponder]. Если он возвращает YES, тогда клавиатура активна.

Ответ 16

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

UIKeyboardDidShowNotification, UIKeyboardDidHideNotification

Например, я могу использовать следующий код для прослушивания уведомления о клавиатуре

//Прослушивание появления и исчезновения клавиатуры

[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(keyboardDidShow:)
                                             name:UIKeyboardDidShowNotification
                                           object:nil];

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardDidHide:)
                                             name:UIKeyboardDidHideNotification
                                           object:nil];

в методах, которые я могу получить уведомления

- (void)keyboardDidShow: (NSNotification *) notifyKeyBoardShow{
    // key board is closed
}

- (void)keyboardDidHide: (NSNotification *) notifyKeyBoardHide{
    // key board is opened
}

Ответ 17

Swift 4

extension UIViewController {
    func registerKeyboardNotifications() {
        let center = NotificationCenter.default
        center.addObserver(self, selector: #selector(keyboardWillBeShown(note:)), name: Notification.Name.UIKeyboardWillShow, object: nil)
        center.addObserver(self, selector: #selector(keyboardWillBeHidden(note:)), name: Notification.Name.UIKeyboardWillHide, object: nil)
    }

    func removeKeyboardNotifications() {
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)

    }

    @objc
    func keyboardWillBeShown(note: Notification) {}

    @objc
    func keyboardWillBeHidden(note: Notification) {}

}

final class MyViewController: UIViewController {

    // MARK: - Properties
    var isKeyboardVisible = false

    // MARK: - Life Cycle
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        registerKeyboardNotifications()
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        removeKeyboardNotifications()
    }

    // MARK: - Keyboard Handling
    override func keyboardWillBeShown(note: Notification) {
        isKeyboardVisible = true
        let userInfo = note.userInfo
        let keyboardFrame = userInfo?[UIKeyboardFrameEndUserInfoKey] as! CGRect
        let contentInset = UIEdgeInsetsMake(0.0, 0.0, keyboardFrame.height, 0.0)
        tableView.contentInset = contentInset
    }

   override func keyboardWillBeHidden(note: Notification) {
        tableView.contentInset = .zero
        isKeyboardVisible = false
   }

   // MARK: - Test
   fileprivate func test() {
        if isKeyboardVisible { // do something
        }
   }
}

Ответ 18

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

-(BOOL)isKeyboardActiveInView:(UIView *)view {
    for (UIView *anyView in [view subviews]) {
        if ([anyView isKindOfClass:[UITextField class]]) {
            if (((UITextField *)anyView).isFirstResponder) {
                return YES;
            }
        } else if ([anyView isKindOfClass:[UILabel class]]) {
            if (((UILabel *)anyView).isFirstResponder) {
                return YES;
            }
        } else if ([anyView isKindOfClass:[UITextView class]]) {
            if (((UITextView *)anyView).isFirstResponder) {
                return YES;
            }
        } else {
            if ([self isKeyboardActiveInView:anyView]) {
                return YES;
            }
        }
    }
    return NO;
}

Ответ 19

SWIFT 4.2/SWIFT 5

class Listener {
   public static let shared = Listener()
   var isVisible = false

   // Start this listener if you want to present the toast above the keyboard.
   public func startKeyboardListener() {
      NotificationCenter.default.addObserver(self, selector: #selector(didShow), name: UIResponder.keyboardWillShowNotification, object: nil)
      NotificationCenter.default.addObserver(self, selector: #selector(didHide), name: UIResponder.keyboardWillHideNotification, object: nil)
   }

   @objc func didShow() {
     isVisible = true
   }

    @objc func didHide(){
       isVisible = false
    }
}

Ответ 20

Я думаю, это может помочь u,

+(BOOL)isKeyBoardInDisplay  {

    BOOL isExists = NO;
    for (UIWindow *keyboardWindow in [[UIApplication sharedApplication] windows])   {
        if ([[keyboardWindow description] hasPrefix:@"<UITextEffectsWindow"] == YES) {
            isExists = YES;
        }  
    }

    return isExists;
}

спасибо,

Навен Шань