How can I programmatically check whether a keyboard is present in iOS app?

IosObjective CKeyboard

Ios Problem Overview


I need to check the condition of keyboard visibility in my iOS app.

Pseudocode:

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

How can I check this condition?

Ios Solutions


Solution 1 - Ios

…or take the easy way:

When you enter a textField, it becomes first responder and the keyboard appears. You can check the status of the keyboard with [myTextField isFirstResponder]. If it returns YES, then the the keyboard is active.

Solution 2 - Ios

drawnonward's code is very close, but collides with UIKit's namespace and could be made easier to use.

@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

Solution 3 - Ios

Create a UIKeyboardListener when you know the keyboard is not visible, for example by calling [UIKeyboardListener shared] from 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

Solution 4 - Ios

I think you need to use the notifications that are provided about the keyboard:

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

> Keyboard Notifications > > When the system shows or hides the > keyboard, it posts several keyboard > notifications. These notifications > contain information about the > keyboard, including its size, which > you can use for calculations that > involve moving views. Registering for > these notifications is the only way to > get some types of information about > the keyboard. The system delivers the > following notifications for > keyboard-related events: > > * UIKeyboardWillShowNotification > * UIKeyboardDidShowNotification > * UIKeyboardWillHideNotification > * UIKeyboardDidHideNotification > > For more information about these > notifications, see their descriptions > in UIWindow Class Reference. For > information about how to show and hide > the keyboard, see Text and Web.

Solution 5 - Ios

Add an extension

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

Then check if keyboard is present,

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

Solution 6 - Ios

Swift 3 Implementation

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

Solution 7 - Ios

Using the window subview hierarchy as indication for keyboard showing is a hack. If Apple changers their underlying implementation all these answers would break.

The correct way would be to monitor Keyboard show and hide notifications application wide such as inside your App Delegate:

In AppDelegate.h:

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (assign, nonatomic) BOOL keyboardIsShowing;

@end

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

Then you can check using:

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

It should be noted the keyboard show/hide notifications will not fire when user is using a bluetooth or external keyboard.

Solution 8 - Ios

This is from the iOS Text Programming Guide published by Apple here: https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html

Basically call "registerForKeyBoardNotifications" in your ViewDidLoad. Then every time the keyboard becomes active, "keyboardWasShown" is called. And every time the keyboard disappears, "keyboardWillBeHidden" is called.

// 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's 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;
}

Solution 9 - Ios

Now in iOS8 this solution of course doesn't work. It was written initially for IOS4/5.

Try this solution:

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

Solution 10 - Ios

A few observations:

The recommended pattern for a singleton object would be as follows. dispatch_once makes sure the class is initialised once in a thread-safe way, and the static variable isn't visible outside. And it's standard GCD, so no need to know about low level details of Objective-C.

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

    return shared;
}

Usually you don't want to know just whether the keyboard is visible or not, but how big it is. Keyboards don't all have the same size. iPhone keyboards are smaller than iPad keyboards. So you'd want another property @property (readonly, nonatomic) CGRect keyboardRect; which is set in the noticeShowKeyboard: method like this:

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

Important to notice that the rectangle is in UIWindow coordinates and doesn't respect screen rotation. So the caller would convert that rectangle by calling

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

If the user rotates the screen while the keyboard is visible, the app will be told that the keyboard is hidden, then shown again. When it is shown, other views are most likely not rotated yet. So if you observe keyboard hide/show events yourself, convert the coordinates when you actually need them, not in the notification.

If the user splits or undocks the keyboard, or uses a hardware keyboard, the notifications will always show the keyboard as hidden. Undocking or merging the keyboard will send a "keyboard shown" notification.

The listener must be initialised while the keyboard is hidden, otherwise the first notification will be missed, and it will be assumed that the keyboard is hidden when it's not.

So it is quite important to know what you actually want. This code is useful to move things out of the way of the keyboard (with a split or undocked keyboard, that's the responsibility of the user). It doesn't tell you whether the user can see a keyboard on the screen (in case of a split keyboard). It doesn't tell you whether the user can type (for example when there is a hardware keyboard). Looking at other windows doesn't work if the app creates other windows itself.

Solution 11 - Ios

Swift implementation:

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

Because swift doesn't execute class load method on startup it is important to start this service on app launch:

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

Solution 12 - Ios

This is my solution, it encapsulates everything into a single static method, and you can call it anywhere to check:

+(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;
}

Solution 13 - Ios

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

Solution 14 - Ios

And here's how to do it in 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");
}

Don't forget to unregister:

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

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

And if you want to dismiss keyboard on pressing the "Return" button:

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

}

Solution 15 - Ios

Try this function

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: https://stackoverflow.com/questions/6457239/ios-how-to-access-the-uikeyboard

Solution 16 - Ios

BOOL isTxtOpen = [txtfieldObjct isFirstReponder]. If it returns YES, then the the keyboard is active.

Solution 17 - Ios

To check weather keyboard is appeared, we can use the Keyboard predefined notifications.

UIKeyboardDidShowNotification ,UIKeyboardDidHideNotification

For example I can use the following code to listen the keyboard notification

// Listen for keyboard appearances and disappearances

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

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

in the methods I can get notifications

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

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

Solution 18 - Ios

SwiftUI - Full Example

import SwiftUI

struct ContentView: View {
    
    @State private var text = defaultText
    
    @State private var isKeyboardShowing = false
    
    private static let defaultText = "write something..."
    
    private var gesture = TapGesture().onEnded({_ in
        UIApplication.shared.endEditing(true)
    })
    
    var body: some View {
        
        ZStack {
            Color.black
            
            VStack(alignment: .leading) {
                TextField("placeholder", text: $text)
                    .foregroundColor(.white)
                    .padding()
                    .background(Color.green)
            }
            
            .padding()
        }
        .edgesIgnoringSafeArea(.all)
        .onChange(of: isKeyboardShowing, perform: { (isShowing) in
            if isShowing {
                if text == Self.defaultText { text = "" }
            } else {
                if text == "" { text = Self.defaultText }
            }
        })
        .simultaneousGesture(gesture)
        .onReceive(NotificationCenter.default
                    .publisher(for: UIResponder.keyboardWillShowNotification), perform: { (value) in
                        isKeyboardShowing = true
                    })
        .onReceive(NotificationCenter.default
                    .publisher(for: UIResponder.keyboardWillHideNotification), perform: { (value) in
                        isKeyboardShowing = false
                    })
    }
}

extension UIApplication {
    func endEditing(_ force: Bool) {
        self.windows
            .filter{$0.isKeyWindow}
            .first?
            .endEditing(force)
    }
}

Solution 19 - Ios

You can iteratively check all textviews, textfields, and labels in the subviews of a parent view to see if any are the first responder with something like this:

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

Solution 20 - Ios

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

Solution 21 - Ios

I think this may help u,

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

thanks,

Naveen Shan

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJitendra SinghView Question on Stackoverflow
Solution 1 - IosthpitschView Answer on Stackoverflow
Solution 2 - IosrpetrichView Answer on Stackoverflow
Solution 3 - IosdrawnonwardView Answer on Stackoverflow
Solution 4 - IosbeggsView Answer on Stackoverflow
Solution 5 - IosRashid KCView Answer on Stackoverflow
Solution 6 - IosChristos ChadjikyriacouView Answer on Stackoverflow
Solution 7 - IosVladView Answer on Stackoverflow
Solution 8 - IosScuttleView Answer on Stackoverflow
Solution 9 - IosmalexView Answer on Stackoverflow
Solution 10 - IosChrisView Answer on Stackoverflow
Solution 11 - IosKrešimir PrcelaView Answer on Stackoverflow
Solution 12 - IospthrView Answer on Stackoverflow
Solution 13 - IosAmber KView Answer on Stackoverflow
Solution 14 - IosTeodor CiuraruView Answer on Stackoverflow
Solution 15 - IosVanguarderView Answer on Stackoverflow
Solution 16 - IosHardik MamtoraView Answer on Stackoverflow
Solution 17 - IosManoj SinghalView Answer on Stackoverflow
Solution 18 - IosPeter KreinzView Answer on Stackoverflow
Solution 19 - IosAlbert RenshawView Answer on Stackoverflow
Solution 20 - IosAmrit SidhuView Answer on Stackoverflow
Solution 21 - IosNaveen ShanView Answer on Stackoverflow